X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fpoll.c;h=b3eda5d3d445672fd690c3a9a30c7082b89c74d6;hb=90f8d0d3e4ce4b1f4118d35eba6a051558323ace;hp=80708854961542a9874fdba3cc2312cb7740e932;hpb=222b0486b7db1b09293e05512873d633440efcb3;p=gnulib.git diff --git a/lib/poll.c b/lib/poll.c index 807088549..b3eda5d3d 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, 2008 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 -#endif +#include #include #include "poll.h" @@ -31,23 +29,23 @@ #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 -#ifndef EOVERFLOW -#define EOVERFLOW EINVAL +/* BeOS does not have MSG_PEEK. */ +#ifndef MSG_PEEK +#define MSG_PEEK 0 #endif int @@ -58,9 +56,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 +126,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; }