1 /* Emulation for poll(2)
2 Contributed by Paolo Bonzini.
4 Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
6 This file is part of gnulib.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation,
20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
24 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <sys/select.h>
32 #ifdef HAVE_SYS_IOCTL_H
33 #include <sys/ioctl.h>
35 #ifdef HAVE_SYS_FILIO_H
36 #include <sys/filio.h>
39 #if TIME_WITH_SYS_TIME
40 # include <sys/time.h>
44 # include <sys/time.h>
55 #define EOVERFLOW EINVAL
59 poll (pfd, nfd, timeout)
64 fd_set rfds, wfds, efds;
65 struct timeval tv, *ptv;
66 int maxfd, rc, happened;
70 if (nfd > sysconf (_SC_OPEN_MAX))
75 #else /* !_SC_OPEN_MAX */
82 #endif /* OPEN_MAX -- else, no check is needed */
83 #endif /* !_SC_OPEN_MAX */
85 /* EFAULT is not necessary to implement, but let's do it in the
93 /* convert timeout number into a timeval structure */
97 /* return immediately or after timeout */
98 ptv->tv_sec = timeout / 1000;
99 ptv->tv_usec = (timeout % 1000) * 1000;
101 else if (timeout == INFTIM)
110 /* create fd sets and determine max fd */
115 for (i = 0; i < nfd; i++)
120 if (pfd[i].events & (POLLIN | POLLRDNORM))
121 FD_SET (pfd[i].fd, &rfds);
123 /* see select(2): "the only exceptional condition detectable
124 is out-of-band data received on a socket", hence we push
125 POLLWRBAND events onto wfds instead of efds. */
126 if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
127 FD_SET (pfd[i].fd, &wfds);
128 if (pfd[i].events & (POLLPRI | POLLRDBAND))
129 FD_SET (pfd[i].fd, &efds);
130 if (pfd[i].fd >= maxfd
131 && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
132 | POLLRDNORM | POLLRDBAND
133 | POLLWRNORM | POLLWRBAND)))
136 if (maxfd > FD_SETSIZE)
144 /* examine fd sets */
145 rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
147 /* establish results */
151 for (i = 0; i < nfd; i++)
158 if (FD_ISSET (pfd[i].fd, &rfds))
162 /* support for POLLHUP. */
163 #if defined __MACH__ && defined __APPLE__
164 /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK for
165 some kinds of descriptors. Use FIONREAD to emulate POLLHUP.
166 It is still not completely POSIX compliant (it does not fully
167 work on TTYs), but at least it does not delete data! For other
168 platforms, we still use MSG_PEEK because it was proved to be
169 reliable, and I a leery of changing it. */
171 r = ioctl (pfd[i].fd, FIONREAD, &avail);
172 while (r == -1 && (errno == EAGAIN || errno == EINTR));
177 r = recv (pfd[i].fd, data, 64, MSG_PEEK);
180 avail = (errno == ESHUTDOWN || errno == ECONNRESET ||
181 errno == ECONNABORTED || errno == ENETRESET) ? 0 : -1;
188 /* An hung up descriptor does not increase the return value! */
190 pfd[i].revents |= POLLHUP;
191 else if (avail == -1)
192 pfd[i].revents |= POLLERR;
194 happened |= POLLIN | POLLRDNORM;
197 if (FD_ISSET (pfd[i].fd, &wfds))
198 happened |= POLLOUT | POLLWRNORM | POLLWRBAND;
200 if (FD_ISSET (pfd[i].fd, &efds))
201 happened |= POLLPRI | POLLRDBAND;
203 pfd[i].revents |= pfd[i].events & happened;
204 rc += (happened > 0);