Back to index

glibc  2.9
poll.c
Go to the documentation of this file.
00001 /* Copyright (C) 1994,1996,1997,1998,1999,2001,2002
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <alloca.h>
00021 #include <sys/poll.h>
00022 #include <sys/types.h>
00023 #include <errno.h>
00024 #include <string.h>
00025 #include <sys/time.h>
00026 #include <sys/param.h>
00027 #include <unistd.h>
00028 
00029 /* Poll the file descriptors described by the NFDS structures starting at
00030    FDS.  If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
00031    an event to occur; if TIMEOUT is -1, block until an event occurs.
00032    Returns the number of file descriptors with events, zero if timed out,
00033    or -1 for errors.  */
00034 
00035 int
00036 __poll (fds, nfds, timeout)
00037      struct pollfd *fds;
00038      nfds_t nfds;
00039      int timeout;
00040 {
00041   static int max_fd_size;
00042   struct timeval tv;
00043   fd_set *rset, *wset, *xset;
00044   struct pollfd *f;
00045   int ready;
00046   int maxfd = 0;
00047   int bytes;
00048 
00049   if (!max_fd_size)
00050     max_fd_size = __getdtablesize ();
00051 
00052   bytes = howmany (max_fd_size, __NFDBITS);
00053   rset = alloca (bytes);
00054   wset = alloca (bytes);
00055   xset = alloca (bytes);
00056 
00057   /* We can't call FD_ZERO, since FD_ZERO only works with sets
00058      of exactly __FD_SETSIZE size.  */
00059   __bzero (rset, bytes);
00060   __bzero (wset, bytes);
00061   __bzero (xset, bytes);
00062 
00063   for (f = fds; f < &fds[nfds]; ++f)
00064     {
00065       f->revents = 0;
00066       if (f->fd >= 0)
00067        {
00068          if (f->fd >= max_fd_size)
00069            {
00070              /* The user provides a file descriptor number which is higher
00071                than the maximum we got from the `getdtablesize' call.
00072                Maybe this is ok so enlarge the arrays.  */
00073              fd_set *nrset, *nwset, *nxset;
00074              int nbytes;
00075 
00076              max_fd_size = roundup (f->fd, __NFDBITS);
00077              nbytes = howmany (max_fd_size, __NFDBITS);
00078 
00079              nrset = alloca (nbytes);
00080              nwset = alloca (nbytes);
00081              nxset = alloca (nbytes);
00082 
00083              __bzero ((char *) nrset + bytes, nbytes - bytes);
00084              __bzero ((char *) nwset + bytes, nbytes - bytes);
00085              __bzero ((char *) nxset + bytes, nbytes - bytes);
00086 
00087              rset = memcpy (nrset, rset, bytes);
00088              wset = memcpy (nwset, wset, bytes);
00089              xset = memcpy (nxset, xset, bytes);
00090 
00091              bytes = nbytes;
00092            }
00093 
00094          if (f->events & POLLIN)
00095            FD_SET (f->fd, rset);
00096          if (f->events & POLLOUT)
00097            FD_SET (f->fd, wset);
00098          if (f->events & POLLPRI)
00099            FD_SET (f->fd, xset);
00100          if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
00101            maxfd = f->fd;
00102        }
00103     }
00104 
00105   tv.tv_sec = timeout / 1000;
00106   tv.tv_usec = (timeout % 1000) * 1000;
00107 
00108   while (1)
00109     {
00110       ready = __select (maxfd + 1, rset, wset, xset,
00111                      timeout == -1 ? NULL : &tv);
00112 
00113       /* It might be that one or more of the file descriptors is invalid.
00114         We now try to find and mark them and then try again.  */
00115       if (ready == -1 && errno == EBADF)
00116        {
00117          fd_set *sngl_rset = alloca (bytes);
00118          fd_set *sngl_wset = alloca (bytes);
00119          fd_set *sngl_xset = alloca (bytes);
00120          struct timeval sngl_tv;
00121 
00122          /* Clear the original set.  */
00123          __bzero (rset, bytes);
00124          __bzero (wset, bytes);
00125          __bzero (xset, bytes);
00126 
00127          /* This means we don't wait for input.  */
00128          sngl_tv.tv_sec = 0;
00129          sngl_tv.tv_usec = 0;
00130 
00131          maxfd = -1;
00132 
00133          /* Reset the return value.  */
00134          ready = 0;
00135 
00136          for (f = fds; f < &fds[nfds]; ++f)
00137            if (f->fd != -1 && (f->events & (POLLIN|POLLOUT|POLLPRI))
00138               && (f->revents & POLLNVAL) == 0)
00139              {
00140               int n;
00141 
00142               __bzero (sngl_rset, bytes);
00143               __bzero (sngl_wset, bytes);
00144               __bzero (sngl_xset, bytes);
00145 
00146               if (f->events & POLLIN)
00147                 FD_SET (f->fd, sngl_rset);
00148               if (f->events & POLLOUT)
00149                 FD_SET (f->fd, sngl_wset);
00150               if (f->events & POLLPRI)
00151                 FD_SET (f->fd, sngl_xset);
00152 
00153               n = __select (f->fd + 1, sngl_rset, sngl_wset, sngl_xset,
00154                            &sngl_tv);
00155               if (n != -1)
00156                 {
00157                   /* This descriptor is ok.  */
00158                   if (f->events & POLLIN)
00159                     FD_SET (f->fd, rset);
00160                   if (f->events & POLLOUT)
00161                     FD_SET (f->fd, wset);
00162                   if (f->events & POLLPRI)
00163                     FD_SET (f->fd, xset);
00164                   if (f->fd > maxfd)
00165                     maxfd = f->fd;
00166                   if (n > 0)
00167                     /* Count it as being available.  */
00168                     ++ready;
00169                 }
00170               else if (errno == EBADF)
00171                 f->revents |= POLLNVAL;
00172              }
00173          /* Try again.  */
00174          continue;
00175        }
00176 
00177       break;
00178     }
00179 
00180   if (ready > 0)
00181     for (f = fds; f < &fds[nfds]; ++f)
00182       {
00183        if (f->fd >= 0)
00184          {
00185            if (FD_ISSET (f->fd, rset))
00186              f->revents |= POLLIN;
00187            if (FD_ISSET (f->fd, wset))
00188              f->revents |= POLLOUT;
00189            if (FD_ISSET (f->fd, xset))
00190              f->revents |= POLLPRI;
00191          }
00192       }
00193 
00194   return ready;
00195 }
00196 #ifndef __poll
00197 libc_hidden_def (__poll)
00198 weak_alias (__poll, poll)
00199 #endif