X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fpoll.c;h=ed81dbaafb85f4feb82533833c9480251e857fa9;hb=c532b2a8ef48d317a1bc348584c00880ea7c5ba6;hp=bc200f515d1cfb49266492a0e5a03afed774ec27;hpb=267a39bafd249d7eb9c37df06dc6defcf41cb343;p=gnulib.git diff --git a/lib/poll.c b/lib/poll.c index bc200f515..ed81dbaaf 100644 --- a/lib/poll.c +++ b/lib/poll.c @@ -1,7 +1,7 @@ /* Emulation for poll(2) Contributed by Paolo Bonzini. - Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright 2001, 2002, 2003, 2006, 2007 Free Software Foundation, Inc. This file is part of gnulib. @@ -19,9 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif #include #include "poll.h" @@ -31,17 +29,16 @@ #include #include -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_FILIO_H +#include #endif +#include +#include + #ifndef INFTIM #define INFTIM (-1) #endif @@ -50,6 +47,11 @@ #define EOVERFLOW EINVAL #endif +/* BeOS does not have MSG_PEEK. */ +#ifndef MSG_PEEK +#define MSG_PEEK 0 +#endif + int poll (pfd, nfd, timeout) struct pollfd *pfd; @@ -58,9 +60,8 @@ poll (pfd, nfd, timeout) { fd_set rfds, wfds, efds; struct timeval tv, *ptv; - int maxfd, rc, happened; + int maxfd, rc; nfds_t i; - char data[64]; #ifdef _SC_OPEN_MAX if (nfd > sysconf (_SC_OPEN_MAX)) @@ -129,52 +130,77 @@ poll (pfd, nfd, timeout) | POLLWRNORM | POLLWRBAND))) { maxfd = pfd[i].fd; + + /* Windows use a linear array of sockets (of size FD_SETSIZE). The + descriptor value is not used to address the array. */ +#if defined __CYGWIN__ || (!defined _WIN32 && !defined __WIN32__) if (maxfd > FD_SETSIZE) { errno = EOVERFLOW; return -1; } +#endif } } /* examine fd sets */ rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv); + if (rc < 0) + return rc; /* establish results */ - if (rc > 0) - { - rc = 0; - for (i = 0; i < nfd; i++) - { - pfd[i].revents = 0; - if (pfd[i].fd < 0) - continue; - - happened = 0; - if (FD_ISSET (pfd[i].fd, &rfds)) - { - /* support for POLLHUP. An hung up descriptor does not - increase the return value! */ - if (recv (pfd[i].fd, data, 64, MSG_PEEK) == -1) - { - if (errno == ESHUTDOWN || errno == ECONNRESET - || errno == ECONNABORTED || errno == ENETRESET) - pfd[i].revents |= POLLHUP; - } - else - happened |= POLLIN | POLLRDNORM; - } - - if (FD_ISSET (pfd[i].fd, &wfds)) - happened |= POLLOUT | POLLWRNORM | POLLWRBAND; - - if (FD_ISSET (pfd[i].fd, &efds)) - happened |= POLLPRI | POLLRDBAND; - - pfd[i].revents |= pfd[i].events & happened; - rc += (happened > 0); - } - } + rc = 0; + for (i = 0; i < nfd; i++) + if (pfd[i].fd < 0) + pfd[i].revents = 0; + else + { + int happened = 0, sought = pfd[i].events; + if (FD_ISSET (pfd[i].fd, &rfds)) + { + int r; + +#if defined __MACH__ && defined __APPLE__ + /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK + for some kinds of descriptors. Detect if this descriptor is a + connected socket, a server socket, or something else using a + 0-byte recv, and use ioctl(2) to detect POLLHUP. */ + r = recv (pfd[i].fd, NULL, 0, MSG_PEEK); + if (r == 0 || errno == ENOTSOCK) + ioctl(pfd[i].fd, FIONREAD, &r); +#else + char data[64]; + r = recv (pfd[i].fd, data, sizeof (data), MSG_PEEK); +#endif + if (r == 0) + happened |= POLLHUP; + + /* If the event happened on an unconnected server socket, + that's fine. */ + else if (r > 0 || ( /* (r == -1) && */ errno == ENOTCONN)) + happened |= (POLLIN | POLLRDNORM) & sought; + + /* Distinguish hung-up sockets from other errors. */ + else if (errno == ESHUTDOWN || errno == ECONNRESET + || errno == ECONNABORTED || errno == ENETRESET) + happened |= POLLHUP; + + else + happened |= POLLERR; + } + + if (FD_ISSET (pfd[i].fd, &wfds)) + happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought; + + if (FD_ISSET (pfd[i].fd, &efds)) + happened |= (POLLPRI | POLLRDBAND) & sought; + + if (happened) + { + pfd[i].revents = happened; + rc++; + } + } return rc; }