Subject: lib/1803: NetBSD has no userland poll() implementation
To: None <gnats-bugs@NetBSD.ORG>
From: Jason R. Thorpe <thorpej@mail.CS.ORST.EDU>
List: netbsd-bugs
Date: 12/01/1995 13:52:09
>Number:         1803
>Category:       lib
>Synopsis:       NetBSD has no userland poll() implementation
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    lib-bug-people (Library Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Fri Dec  1 17:05:00 1995
>Last-Modified:
>Originator:     
>Organization:
Network for Education and Research in Oregon
>Release:        1.0
>Environment:
	
System: NetBSD helix 1.0 NetBSD 1.0 (HELIX) #50: Mon Jul 24 14:23:51 PDT 1995 romansz@helix:/usr/src/sys/arch/hp300/compile/HELIX hp300


>Description:
	About a year ago, I was porting a SVR4 application to NetBSD 1.0.
	Several of the 70-or-so files contained calls to poll().  Rather
	than modifying all of the code to use select(), I decided it was
	easier to write a short library function to emulate poll() using
	select().

	This discussion came up recently on a NetBSD mailing list, and
	due to popular demand, I've shar'd up the code I wrote and
	am submitting this change request that it be included in
	one of the NetBSD system libraries.  The most appropriate
	place for it is probably in libcompat, under the directory
	.../sysv/.

>How-To-Repeat:
	N/A.

>Fix:
	Attached below is a shar file of my poll() "emulator" (more like
	"approximator").  Included are poll.c, poll.3, and poll.h.
	The code was written a year ago, so I've touched it up a bit...
	Well, replaced a getdtablesize() with a call to sysconf().

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	poll.3
#	poll.c
#	poll.h
#
echo x - poll.3
sed 's/^X//' >poll.3 << 'END-of-poll.3'
X.\"
X.\" Copyright (c) 1994 Jason R. Thorpe
X.\" All rights reserved.
X.\"
X.\" Redistribution and use in source and binary forms, with or without
X.\" modification, are permitted provided that the following conditions
X.\" are met:
X.\" 1. Redistributions of source code must retain the above copyright
X.\"    notice, this list of conditions and the following disclaimer.
X.\" 2. Redistributions in binary form must reproduce the above copyright
X.\"    notice, this list of conditions and the following disclaimer in the
X.\"    documentation and/or other materials provided with the distribution.
X.\" 3. All advertising materials mentioning features or use of this software
X.\"    must display the following acknowledgement:
X.\"	This product includes software developed by Jason R. Thorpe.
X.\" 4. The name of the author may not be used to endorse or promote products
X.\"    derived from this software without specific prior written permission.
X.\"
X.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
X.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
X.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
X.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
X.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
X.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X.\"
X.Dd December 13, 1994
X.Dt POLL 3
X.Os NetBSD
X.Sh NAME
X.Nm poll
X.Nd synchronous I/O multiplexing
X.Sh SYNOPSIS
X.Fd #include <poll.h>
X.Ft int
X.Fn poll "struct pollfd *fds" "int nfds" "int timeout"
X.Sh DESCRIPTION
X.Fn Poll
Xprovides a mechanism for reporting I/O conditions across a set of file
Xdescriptors.
X.Pp
XThe arguments are as follows:
X.Bl -tag -width timeout
X.It Pa fds
XPoints to an array of
X.Nm pollfd
Xstructures, which are defined as:
X.Bd -literal -offset indent
Xstruct pollfd {
X	int fd;
X	short events;
X	short revents;
X};
X.Ed
X.Pp
XThe
X.Pa fd
Xmember is an open file descriptor.  The
X.Pa events
Xand
X.Pa revents
Xmembers are bitmasks of conditions to monitor and conditions found,
Xrespectively.
X.It Pa nfds
XThe number of
X.Nm pollfd
Xstructures in the array.
X.It Pa timeout
XMaximum interval to wait for the poll to complete, in milliseconds.  If
Xthis value is 0, then
X.Fn poll
Xwill return immediately.  If this value is less than 0,
X.Fn poll
Xwill block indefinitely until a condition is found.
X.El
X.Pp
XThe calling process sets the
X.Pa events
Xbitmask and
X.Fn poll
Xsets the
X.Pa revents
Xbitmask.  Each call to
X.Fn poll
Xresets the
X.Pa revents
Xbitmask for accuracy.  The condition flags in the bitmasks are defined as:
X.Bl -tag -width POLLRDNORM
X.It Nm POLLIN
XData is available on the file descriptor for reading.
X.It Nm POLLNORM
XSame as
X.Nm POLLIN .
X.It Nm POLLPRI
XSame as
X.Nm POLLIN .
X.It Nm POLLOUT
XData can be written to the file descriptor without blocking.
X.It Nm POLLERR
XThis flag is not used in this implementation and is provided only for source
Xcode compatibility.
X.It Nm POLLHUP
XThe file descriptor was valid before the polling process and invalid after.
XPresumably, this means that the file descriptor was closed sometime during
Xthe poll.
X.It Nm POLLNVAL
XThe corresponding file descriptor is invalid.
X.It Nm POLLRDNORM
XSame as
X.Nm POLLIN .
X.It Nm POLLRDBAND
XSame as
X.Nm POLLIN .
X.It Nm POLLWRNORM
XSame as
X.Nm POLLOUT .
X.It Nm POLLWRBAND
XSame as
X.Nm POLLOUT .
X.It Nm POLLMSG
XThis flag is not used in this implementation and is provided only for source
Xcode compatibility.
X.El
X.Pp
XAll flags except
X.Nm POLLIN ,
X.Nm POLLOUT ,
Xand their synonyms are for use only in the
X.Pa revents
Xmember of the
X.Nm pollfd
Xstructure.  An attempt to set any of these flags in the
X.Pa events
Xmember will generate an error condition.
X.Pp
XIn addition to I/O multiplexing,
X.Fn poll
Xcan be used to generate simple timeouts.  This functionality may be achieved
Xby passing a NULL pointer for
X.Pa fds .
X.Sh WARNINGS
XSince this implementation is a wrapper around
X.Fn select ,
Xfunctionality is limited to such.  There is no differentiation between
Xstandard and priority messages in the read or write queues.
X.Pp
XThe
X.Nm POLLHUP
Xflag is only a close approximation and may not always be accurate.
X.Sh RETURN VALUES
XUpon error,
X.Fn poll
Xreturns a -1 and sets the global variable
X.Pa errno
Xto indicate the error.  If the timeout interval was reached before any events
Xoccurred, a 0 is returned.  Otherwise,
X.Fn poll
Xreturns the number of file descriptors for which
X.Pa revents
Xis non-zero.
X.Sh ERRORS
X.Fn Poll
Xwill fail if:
X.Bl -tag -width "EINVAL   "
X.It Bq Er EINVAL
X.Pa nfds
Xwas either a negative number or greater than the number of available
Xfile descriptors.
X.It Bq Er EINVAL
XAn invalid flags was set in the
X.Pa events
Xmember of the
X.Nm pollfd
Xstructure.
X.It Bq Er EINVAL
XThe timeout passed to
X.Fn select
Xwas too large.
X.It Bq Er EAGAIN
XResource allocation failed inside of
X.Fn poll .
XSubsequent calls to
X.Fn poll
Xmay succeed.
X.It Bq Er EINTR
X.Fn Select
Xcaught a signal during the polling process.
X.El
X.Sh SEE ALSO
X.Xr sysconf 3 ,
X.Xr select 2
X.Sh HISTORY
XA
X.Fn poll
Xsystem call appeared in
X.At V
END-of-poll.3
echo x - poll.c
sed 's/^X//' >poll.c << 'END-of-poll.c'
X/*
X * Copyright (c) 1994 Jason R. Thorpe.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by Jason R. Thorpe.
X * 4. The name of the author may not be used to endorse or promote products
X *    derived from this software without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
X * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
X * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
X * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
X * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X */
X
X/*
X * Approximate the System V system call ``poll()'' with select(2).
X */
X
X#include <sys/types.h>
X#include <sys/time.h>
X#include <errno.h>
X#include <fcntl.h>
X#include <poll.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X
Xstatic struct timeval *poll_gettimeout __P((int, int *));
X
Xint
Xpoll(fds, nfds, timeout)
X	struct pollfd *fds;
X	int nfds;
X	int timeout;
X{
X	fd_set reads, writes;
X	int i, inval, rval, tsize;
X	struct timeval *tv;
X
X	/*
X	 * If nfds is larger than the number of possible file descriptors
X	 * or less than zero, simply return an error condition now.
X	 */
X	tsize = sysconf(_SC_OPEN_MAX);
X	if (tsize > FD_SETSIZE)
X		tsize = FD_SETSIZE;
X
X	if (nfds < 0 || nfds > tsize) {
X		errno = EINVAL;
X		return (-1);
X	}
X
X	/*
X	 * Special case of a simple timeout with no
X	 * event checking.
X	 */
X	if (fds == NULL) {
X		tv = poll_gettimeout(timeout, &rval);
X		if (rval == -1) {
X			errno = EAGAIN;
X			return (-1);
X		}
X		return (select(tsize, 0, 0, 0, tv));
X	}
X
X	/* initialize the fd_sets and invalids */
X	FD_ZERO(&reads);
X	FD_ZERO(&writes);
X	inval = 0;
X
X	/*
X	 * Run through the file descriptors and:
X	 * a.  clear revents field
X	 * b.  check for validity
X	 * c.  check event and place in appropriate fd_set
X	 */
X	for (i = 0; i < nfds; i++) {
X		/* a.  clear revents field */
X		fds[i].revents = 0;
X
X		/* b.  check validity */
X		if (fcntl(fds[i].fd, F_GETFL, O_NDELAY) == -1) {
X			fds[i].revents |= POLLNVAL;
X			++inval;
X			continue;
X		}
X
X		/* c.  check event and add */
X		if ((fds[i].events == 0) || (fds[i].events & __INVALIDPOLL)) {
X			errno = EINVAL;
X			return (-1);
X		}
X
X		if (fds[i].events & POLLIN)
X			FD_SET(fds[i].fd, &reads);
X
X		if (fds[i].events & POLLOUT)
X			FD_SET(fds[i].fd, &writes);
X	}
X
X	tv = poll_gettimeout(timeout, &rval);
X	if (rval == -1) {
X		errno = EAGAIN;
X		return (-1);
X	}
X
X	/*
X	 * Call select and loop through the descriptors again, checking
X	 * for read and write events.
X	 */
X	if (inval == nfds)
X		return (inval);
X
X	errno = 0;
X
X	rval = select(nfds, &reads, &writes, 0, tv);
X	if (rval < 1)	 	/* timeout or error condition */
X		return (rval);	/* errno will be set by select() */
X		
X	rval = 0;
X	for (i = 0; i < nfds; i++) {
X		if (fds[i].revents & POLLNVAL)
X			continue;
X
X		if (FD_ISSET(fds[i].fd, &reads))
X			fds[i].revents |= POLLIN;
X
X		if (FD_ISSET(fds[i].fd, &writes))
X			fds[i].revents |= POLLOUT;
X
X		/*
X		 * XXX This is only an approximation.  I have no idea
X		 * how accurate this might be.
X		 */
X		if (fcntl(fds[i].fd, F_GETFL, O_NDELAY) == -1)
X			fds[i].revents |= POLLHUP;
X
X		if (fds[i].revents != 0)
X			++rval;
X	}
X	rval += inval;
X
X	return (rval);
X}
X
Xstatic struct timeval *
Xpoll_gettimeout(timeout, rval)
X	int timeout;
X	int *rval;
X{
X	struct timeval *tv;
X
X	if (timeout < 0) {
X		*rval = 0;
X		return (NULL);
X	} else {
X		tv = (struct timeval *) malloc(sizeof(struct timeval));
X		if (tv == NULL) {
X			*rval = -1;
X			return (NULL);
X		}
X
X		tv->tv_usec = timeout * 1000;
X		tv->tv_sec = tv->tv_usec / 1000000;
X		tv->tv_usec %= 1000000;
X
X		return (tv);
X	}
X}
END-of-poll.c
echo x - poll.h
sed 's/^X//' >poll.h << 'END-of-poll.h'
X/*
X * Copyright (c) 1994 Jason R. Thorpe.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by Jason R. Thorpe.
X * 4. The name of the author may not be used to endorse or promote products
X *    derived from this software without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
X * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
X * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
X * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
X * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X */
X
X#ifndef	_POLL_H_
X#define _POLL_H_
X
X#include <sys/types.h>
X#include <sys/cdefs.h>
X
Xstruct pollfd {
X	int fd;
X	short events;
X	short revents;
X};
X
X#define POLLIN		0x0001
X#define POLLNORM	POLLIN
X#define POLLPRI		POLLIN
X#define POLLOUT		0x0008
X#define POLLERR		0x0010		/* not used */
X#define POLLHUP		0x0020
X#define POLLNVAL	0x0040
X#define POLLRDNORM	POLLIN
X#define POLLRDBAND	POLLIN
X#define POLLWRNORM	POLLOUT
X#define POLLWRBAND	POLLOUT
X#define POLLMSG		0x0800		/* not used */
X
X#define __INVALIDPOLL	~(POLLIN | POLLOUT)
X
X__BEGIN_DECLS
Xint poll __P((struct pollfd *, int, int));
X__END_DECLS
X
X#endif /* _POLL_H_ */
END-of-poll.h
exit

>Audit-Trail:
>Unformatted: