/* Emulation for poll(2)
Contributed by Paolo Bonzini.
- Copyright 2001, 2002, 2003, 2006, 2007, 2008 Free Software Foundation, Inc.
+ Copyright 2001-2003, 2006-2009 Free Software Foundation, Inc.
This file is part of gnulib.
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+/* Tell gcc not to warn about the (nfd < 0) tests, below. */
+#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
+# pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
#include <config.h>
#include <alloca.h>
#include <assert.h>
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-#define WIN32_NATIVE
-#include <winsock2.h>
-#include <windows.h>
-#include <io.h>
-#include <stdio.h>
-#include <conio.h>
+# define WIN32_NATIVE
+# include <winsock2.h>
+# include <windows.h>
+# include <io.h>
+# include <stdio.h>
+# include <conio.h>
#else
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <unistd.h>
+# include <sys/time.h>
+# include <sys/socket.h>
+# include <sys/select.h>
+# include <unistd.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
+# include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_FILIO_H
-#include <sys/filio.h>
+# include <sys/filio.h>
#endif
#include <time.h>
#ifndef INFTIM
-#define INFTIM (-1)
+# define INFTIM (-1)
#endif
/* BeOS does not have MSG_PEEK. */
#ifndef MSG_PEEK
-#define MSG_PEEK 0
+# define MSG_PEEK 0
#endif
#ifdef WIN32_NATIVE
+#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
+
+static BOOL
+IsSocketHandle(HANDLE h)
+{
+ WSANETWORKEVENTS ev;
+
+ if (IsConsoleHandle (h))
+ return FALSE;
+
+ /* Under Wine, it seems that getsockopt returns 0 for pipes too.
+ WSAEnumNetworkEvents instead distinguishes the two correctly. */
+ ev.lNetworkEvents = 0xDEADBEEF;
+ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+ return ev.lNetworkEvents != 0xDEADBEEF;
+}
+
/* Declare data structures for ntdll functions. */
typedef struct _FILE_PIPE_LOCAL_INFORMATION {
ULONG NamedPipeType;
typedef DWORD (WINAPI *PNtQueryInformationFile)
(HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
-#ifndef PIPE_BUF
-#define PIPE_BUF 512
-#endif
+# ifndef PIPE_BUF
+# define PIPE_BUF 512
+# endif
-/* Compute revents values for file handle H. */
+/* Compute revents values for file handle H. If some events cannot happen
+ for the handle, eliminate them from *P_SOUGHT. */
static int
-win32_compute_revents (HANDLE h, int sought)
+win32_compute_revents (HANDLE h, int *p_sought)
{
int i, ret, happened;
INPUT_RECORD *irbuffer;
if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
{
if (avail)
- happened |= sought & (POLLIN | POLLRDNORM);
+ happened |= *p_sought & (POLLIN | POLLRDNORM);
}
else
|| fpli.WriteQuotaAvailable >= PIPE_BUF
|| (fpli.OutboundQuota < PIPE_BUF &&
fpli.WriteQuotaAvailable == fpli.OutboundQuota))
- happened |= sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+ happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
}
return happened;
case FILE_TYPE_CHAR:
ret = WaitForSingleObject (h, 0);
- if (ret == WAIT_OBJECT_0)
- {
- nbuffer = avail = 0;
- bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
- if (!bRet || nbuffer == 0)
+ if (!IsConsoleHandle (h))
+ return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
+
+ nbuffer = avail = 0;
+ bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
+ if (bRet)
+ {
+ /* Input buffer. */
+ *p_sought &= POLLIN | POLLRDNORM;
+ if (nbuffer == 0)
return POLLHUP;
+ if (!*p_sought)
+ return 0;
irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
for (i = 0; i < avail; i++)
if (irbuffer[i].EventType == KEY_EVENT)
- return sought & ~(POLLPRI | POLLRDBAND);
+ return *p_sought;
+ return 0;
+ }
+ else
+ {
+ /* Screen buffer. */
+ *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
+ return *p_sought;
}
- break;
default:
ret = WaitForSingleObject (h, 0);
if (ret == WAIT_OBJECT_0)
- return sought & ~(POLLPRI | POLLRDBAND);
+ return *p_sought & ~(POLLPRI | POLLRDBAND);
- break;
+ return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
}
-
- return sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
}
/* Convert fd_sets returned by select into revents values. */
int r;
int socket_errno;
-#if defined __MACH__ && defined __APPLE__
+# 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
socket_errno = (r < 0) ? errno : 0;
if (r == 0 || socket_errno == ENOTSOCK)
ioctl (fd, FIONREAD, &r);
-#else
+# else
char data[64];
r = recv (fd, data, sizeof (data), MSG_PEEK);
socket_errno = (r < 0) ? errno : 0;
-#endif
+# endif
if (r == 0)
happened |= POLLHUP;
int maxfd, rc;
nfds_t i;
-#ifdef _SC_OPEN_MAX
+# ifdef _SC_OPEN_MAX
static int sc_open_max = -1;
if (nfd < 0
errno = EINVAL;
return -1;
}
-#else /* !_SC_OPEN_MAX */
-#ifdef OPEN_MAX
+# else /* !_SC_OPEN_MAX */
+# ifdef OPEN_MAX
if (nfd < 0 || nfd > OPEN_MAX)
{
errno = EINVAL;
return -1;
}
-#endif /* OPEN_MAX -- else, no check is needed */
-#endif /* !_SC_OPEN_MAX */
+# endif /* OPEN_MAX -- else, no check is needed */
+# endif /* !_SC_OPEN_MAX */
/* EFAULT is not necessary to implement, but let's do it in the
simplest case. */
fd_set rfds, wfds, xfds;
BOOL poll_again;
MSG msg;
- char sockbuf[256];
- int rc;
+ int rc = 0;
nfds_t i;
if (nfd < 0 || timeout < -1)
/* Classify socket handles and create fd sets. */
for (i = 0; i < nfd; i++)
{
- size_t optlen = sizeof(sockbuf);
+ int sought = pfd[i].events;
pfd[i].revents = 0;
if (pfd[i].fd < 0)
continue;
- if (!(pfd[i].events & (POLLIN | POLLRDNORM |
- POLLOUT | POLLWRNORM | POLLWRBAND)))
+ if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
+ | POLLPRI | POLLRDBAND)))
continue;
h = (HANDLE) _get_osfhandle (pfd[i].fd);
assert (h != NULL);
-
- /* Under Wine, it seems that getsockopt returns 0 for pipes too.
- WSAEnumNetworkEvents instead distinguishes the two correctly. */
- ev.lNetworkEvents = 0xDEADBEEF;
- WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
- if (ev.lNetworkEvents != 0xDEADBEEF)
+ if (IsSocketHandle (h))
{
int requested = FD_CLOSE;
/* see above; socket handles are mapped onto select. */
- if (pfd[i].events & (POLLIN | POLLRDNORM))
+ if (sought & (POLLIN | POLLRDNORM))
{
requested |= FD_READ | FD_ACCEPT;
FD_SET ((SOCKET) h, &rfds);
}
- if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
+ if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
{
requested |= FD_WRITE | FD_CONNECT;
FD_SET ((SOCKET) h, &wfds);
}
- if (pfd[i].events & (POLLPRI | POLLRDBAND))
+ if (sought & (POLLPRI | POLLRDBAND))
{
requested |= FD_OOB;
FD_SET ((SOCKET) h, &xfds);
}
else
{
- handle_array[nhandles++] = h;
-
- /* Poll now. If we get an event, do not poll again. */
- pfd[i].revents = win32_compute_revents (h, pfd[i].events);
+ /* Poll now. If we get an event, do not poll again. Also,
+ screen buffer handles are waitable, and they'll block until
+ a character is available. win32_compute_revents eliminates
+ bits for the "wrong" direction. */
+ pfd[i].revents = win32_compute_revents (h, &sought);
+ if (sought)
+ handle_array[nhandles++] = h;
if (pfd[i].revents)
wait_timeout = 0;
}
else
{
/* Not a socket. */
+ int sought = pfd[i].events;
+ happened = win32_compute_revents (h, &sought);
nhandles++;
- happened = win32_compute_revents (h, pfd[i].events);
}
if ((pfd[i].revents |= happened) != 0)