summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2003-10-22 09:52:24 +0000
committerEric Andersen <andersen@codepoet.org>2003-10-22 09:52:24 +0000
commit8e8099dcac7317d161b4341dbac5369164397f82 (patch)
tree2312442fff8c670f889eee3c3761703aaee9dc06 /libc/sysdeps/linux
parent7845251d593a343097336f09c8a8b93df2ecc697 (diff)
Per suggestion and patch from Ken Staton, emulates poll using
select for older 2.0 kernels where poll is missing.
Diffstat (limited to 'libc/sysdeps/linux')
-rw-r--r--libc/sysdeps/linux/common/poll.c192
-rw-r--r--libc/sysdeps/linux/common/syscalls.c5
2 files changed, 196 insertions, 1 deletions
diff --git a/libc/sysdeps/linux/common/poll.c b/libc/sysdeps/linux/common/poll.c
new file mode 100644
index 000000000..cf3db35eb
--- /dev/null
+++ b/libc/sysdeps/linux/common/poll.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 1994,1996,1997,1998,1999,2001,2002
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <alloca.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+/* Poll the file descriptors described by the NFDS structures starting at
+ FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
+ an event to occur; if TIMEOUT is -1, block until an event occurs.
+ Returns the number of file descriptors with events, zero if timed out,
+ or -1 for errors. */
+
+int poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+ static int max_fd_size;
+ struct timeval tv;
+ fd_set *rset, *wset, *xset;
+ struct pollfd *f;
+ int ready;
+ int maxfd = 0;
+ int bytes;
+
+ if (!max_fd_size)
+ max_fd_size = getdtablesize ();
+
+ bytes = howmany (max_fd_size, __NFDBITS);
+ rset = alloca (bytes);
+ wset = alloca (bytes);
+ xset = alloca (bytes);
+
+ /* We can't call FD_ZERO, since FD_ZERO only works with sets
+ of exactly __FD_SETSIZE size. */
+ bzero (rset, bytes);
+ bzero (wset, bytes);
+ bzero (xset, bytes);
+
+ for (f = fds; f < &fds[nfds]; ++f)
+ {
+ f->revents = 0;
+ if (f->fd >= 0)
+ {
+ if (f->fd >= max_fd_size)
+ {
+ /* The user provides a file descriptor number which is higher
+ than the maximum we got from the `getdtablesize' call.
+ Maybe this is ok so enlarge the arrays. */
+ fd_set *nrset, *nwset, *nxset;
+ int nbytes;
+
+ max_fd_size = roundup (f->fd, __NFDBITS);
+ nbytes = howmany (max_fd_size, __NFDBITS);
+
+ nrset = alloca (nbytes);
+ nwset = alloca (nbytes);
+ nxset = alloca (nbytes);
+
+ bzero ((char *) nrset + bytes, nbytes - bytes);
+ bzero ((char *) nwset + bytes, nbytes - bytes);
+ bzero ((char *) nxset + bytes, nbytes - bytes);
+
+ rset = memcpy (nrset, rset, bytes);
+ wset = memcpy (nwset, wset, bytes);
+ xset = memcpy (nxset, xset, bytes);
+
+ bytes = nbytes;
+ }
+
+ if (f->events & POLLIN)
+ FD_SET (f->fd, rset);
+ if (f->events & POLLOUT)
+ FD_SET (f->fd, wset);
+ if (f->events & POLLPRI)
+ FD_SET (f->fd, xset);
+ if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
+ maxfd = f->fd;
+ }
+ }
+
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+
+ while (1)
+ {
+ ready = select (maxfd + 1, rset, wset, xset,
+ timeout == -1 ? NULL : &tv);
+
+ /* It might be that one or more of the file descriptors is invalid.
+ We now try to find and mark them and then try again. */
+ if (ready == -1 && errno == EBADF)
+ {
+ fd_set *sngl_rset = alloca (bytes);
+ fd_set *sngl_wset = alloca (bytes);
+ fd_set *sngl_xset = alloca (bytes);
+ struct timeval sngl_tv;
+
+ /* Clear the original set. */
+ bzero (rset, bytes);
+ bzero (wset, bytes);
+ bzero (xset, bytes);
+
+ /* This means we don't wait for input. */
+ sngl_tv.tv_sec = 0;
+ sngl_tv.tv_usec = 0;
+
+ maxfd = -1;
+
+ /* Reset the return value. */
+ ready = 0;
+
+ for (f = fds; f < &fds[nfds]; ++f)
+ if (f->fd != -1 && (f->events & (POLLIN|POLLOUT|POLLPRI))
+ && (f->revents & POLLNVAL) == 0)
+ {
+ int n;
+
+ bzero (sngl_rset, bytes);
+ bzero (sngl_wset, bytes);
+ bzero (sngl_xset, bytes);
+
+ if (f->events & POLLIN)
+ FD_SET (f->fd, sngl_rset);
+ if (f->events & POLLOUT)
+ FD_SET (f->fd, sngl_wset);
+ if (f->events & POLLPRI)
+ FD_SET (f->fd, sngl_xset);
+
+ n = select (f->fd + 1, sngl_rset, sngl_wset, sngl_xset,
+ &sngl_tv);
+ if (n != -1)
+ {
+ /* This descriptor is ok. */
+ if (f->events & POLLIN)
+ FD_SET (f->fd, rset);
+ if (f->events & POLLOUT)
+ FD_SET (f->fd, wset);
+ if (f->events & POLLPRI)
+ FD_SET (f->fd, xset);
+ if (f->fd > maxfd)
+ maxfd = f->fd;
+ if (n > 0)
+ /* Count it as being available. */
+ ++ready;
+ }
+ else if (errno == EBADF)
+ f->revents |= POLLNVAL;
+ }
+ /* Try again. */
+ continue;
+ }
+
+ break;
+ }
+
+ if (ready > 0)
+ for (f = fds; f < &fds[nfds]; ++f)
+ {
+ if (f->fd >= 0)
+ {
+ if (FD_ISSET (f->fd, rset))
+ f->revents |= POLLIN;
+ if (FD_ISSET (f->fd, wset))
+ f->revents |= POLLOUT;
+ if (FD_ISSET (f->fd, xset))
+ f->revents |= POLLPRI;
+ }
+ }
+
+ return ready;
+}
+
diff --git a/libc/sysdeps/linux/common/syscalls.c b/libc/sysdeps/linux/common/syscalls.c
index 6e966f525..0cbec3f08 100644
--- a/libc/sysdeps/linux/common/syscalls.c
+++ b/libc/sysdeps/linux/common/syscalls.c
@@ -1721,9 +1721,12 @@ int getresuid (uid_t *ruid, uid_t *euid, uid_t *suid)
#endif
//#define __NR_poll 168
-#if defined(L_poll) && defined(__NR_poll) /* uClinux 2.0 doesn't have poll */
+#if defined(L_poll) && defined(__NR_poll)
#include <sys/poll.h>
_syscall3(int, poll, struct pollfd *, fds, unsigned long int, nfds, int, timeout);
+#else
+/* uClinux 2.0 doesn't have poll, emulate it using select */
+#include "poll.c"
#endif
//#define __NR_nfsservctl 169