diff options
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/unix/bsd/poll.c | 150 |
1 files changed, 110 insertions, 40 deletions
diff --git a/sysdeps/unix/bsd/poll.c b/sysdeps/unix/bsd/poll.c index 7fb4fcc3fa..5f65e76122 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)) |