about summary refs log tree commit diff
path: root/sysdeps/unix/bsd/poll.c
diff options
context:
space:
mode:
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 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))