aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/unix/bsd/poll.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1999-04-18 01:01:00 +0000
committerUlrich Drepper <drepper@redhat.com>1999-04-18 01:01:00 +0000
commit62acd37630f63718620b8c346a2581c298745b7d (patch)
tree193d11b19a7269fcd5fde30c3994fd0756bd665f /sysdeps/unix/bsd/poll.c
parent1e76ce9c89c4e57dc7cc283326e6a4c86cb0fe61 (diff)
downloadglibc-62acd37630f63718620b8c346a2581c298745b7d.zip
glibc-62acd37630f63718620b8c346a2581c298745b7d.tar.gz
glibc-62acd37630f63718620b8c346a2581c298745b7d.tar.bz2
Update.
1999-04-18 Ulrich Drepper <drepper@cygnus.com> * sysdeps/unix/bsd/poll.c (__poll): Add more compatiblity code to detect and handle invalid descriptors.
Diffstat (limited to 'sysdeps/unix/bsd/poll.c')
-rw-r--r--sysdeps/unix/bsd/poll.c150
1 files changed, 110 insertions, 40 deletions
diff --git a/sysdeps/unix/bsd/poll.c b/sysdeps/unix/bsd/poll.c
index 7fb4fcc..5f65e76 100644
--- a/sysdeps/unix/bsd/poll.c
+++ b/sysdeps/unix/bsd/poll.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1994, 1996, 1997, 1998, 1999 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
@@ -60,52 +60,122 @@ __poll (fds, nfds, timeout)
__bzero (xset, bytes);
for (f = fds; f < &fds[nfds]; ++f)
- 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;
- }
+ {
+ 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;
- ready = __select (maxfd + 1, rset, wset, xset, timeout == -1 ? NULL : &tv);
+ do
+ {
+ 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;
+ }
+ }
+ }
+ while (ready == 0);
+
if (ready > 0)
for (f = fds; f < &fds[nfds]; ++f)
{
- f->revents = 0;
if (f->fd >= 0)
{
if (FD_ISSET (f->fd, rset))