1
/* Emulation for poll(2)
2
Contributed by Paolo Bonzini.
4
Copyright 2001, 2002, 2003, 2006, 2007, 2008 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 Lesser 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 Lesser General Public License for more details.
18
You should have received a copy of the GNU Lesser 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. */
25
#include <sys/types.h>
31
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
40
#include <sys/socket.h>
41
#include <sys/select.h>
45
#ifdef HAVE_SYS_IOCTL_H
46
#include <sys/ioctl.h>
48
#ifdef HAVE_SYS_FILIO_H
49
#include <sys/filio.h>
58
/* BeOS does not have MSG_PEEK. */
65
/* Declare data structures for ntdll functions. */
66
typedef struct _FILE_PIPE_LOCAL_INFORMATION {
68
ULONG NamedPipeConfiguration;
69
ULONG MaximumInstances;
70
ULONG CurrentInstances;
72
ULONG ReadDataAvailable;
74
ULONG WriteQuotaAvailable;
77
} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
79
typedef struct _IO_STATUS_BLOCK
85
ULONG_PTR Information;
86
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
88
typedef enum _FILE_INFORMATION_CLASS {
89
FilePipeLocalInformation = 24
90
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
92
typedef DWORD (WINAPI *PNtQueryInformationFile)
93
(HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
99
/* Compute revents values for file handle H. */
102
win32_compute_revents (HANDLE h, int sought)
106
INPUT_RECORD *irbuffer;
107
DWORD avail, nbuffer;
109
IO_STATUS_BLOCK iosb;
110
FILE_PIPE_LOCAL_INFORMATION fpli;
111
static PNtQueryInformationFile NtQueryInformationFile;
112
static BOOL once_only;
114
switch (GetFileType (h))
119
NtQueryInformationFile = (PNtQueryInformationFile)
120
GetProcAddress (GetModuleHandle ("ntdll.dll"),
121
"NtQueryInformationFile");
126
if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
129
happened |= sought & (POLLIN | POLLRDNORM);
134
/* It was the write-end of the pipe. Check if it is writable.
135
If NtQueryInformationFile fails, optimistically assume the pipe is
136
writable. This could happen on Win9x, where NtQueryInformationFile
137
is not available, or if we inherit a pipe that doesn't permit
138
FILE_READ_ATTRIBUTES access on the write end (I think this should
139
not happen since WinXP SP2; WINE seems fine too). Otherwise,
140
ensure that enough space is available for atomic writes. */
141
memset (&iosb, 0, sizeof (iosb));
142
memset (&fpli, 0, sizeof (fpli));
144
if (!NtQueryInformationFile
145
|| NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
146
FilePipeLocalInformation)
147
|| fpli.WriteQuotaAvailable >= PIPE_BUF
148
|| (fpli.OutboundQuota < PIPE_BUF &&
149
fpli.WriteQuotaAvailable == fpli.OutboundQuota))
150
happened |= sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
155
ret = WaitForSingleObject (h, 0);
156
if (ret == WAIT_OBJECT_0)
159
bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
160
if (!bRet || nbuffer == 0)
163
irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
164
bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
165
if (!bRet || avail == 0)
168
for (i = 0; i < avail; i++)
169
if (irbuffer[i].EventType == KEY_EVENT)
170
return sought & ~(POLLPRI | POLLRDBAND);
175
ret = WaitForSingleObject (h, 0);
176
if (ret == WAIT_OBJECT_0)
177
return sought & ~(POLLPRI | POLLRDBAND);
182
return sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
185
/* Convert fd_sets returned by select into revents values. */
188
win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
192
if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
193
happened |= (POLLIN | POLLRDNORM) & sought;
195
else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
201
r = recv (h, data, sizeof (data), MSG_PEEK);
202
error = WSAGetLastError ();
205
if (r > 0 || error == WSAENOTCONN)
206
happened |= (POLLIN | POLLRDNORM) & sought;
208
/* Distinguish hung-up sockets from other errors. */
209
else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
210
|| error == WSAECONNABORTED || error == WSAENETRESET)
217
if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
218
happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
220
if (lNetworkEvents & FD_OOB)
221
happened |= (POLLPRI | POLLRDBAND) & sought;
228
/* Convert select(2) returned fd_sets into poll(2) revents values. */
230
compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
233
if (FD_ISSET (fd, rfds))
238
#if defined __MACH__ && defined __APPLE__
239
/* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
240
for some kinds of descriptors. Detect if this descriptor is a
241
connected socket, a server socket, or something else using a
242
0-byte recv, and use ioctl(2) to detect POLLHUP. */
243
r = recv (fd, NULL, 0, MSG_PEEK);
244
socket_errno = (r < 0) ? errno : 0;
245
if (r == 0 || socket_errno == ENOTSOCK)
246
ioctl (fd, FIONREAD, &r);
249
r = recv (fd, data, sizeof (data), MSG_PEEK);
250
socket_errno = (r < 0) ? errno : 0;
255
/* If the event happened on an unconnected server socket,
257
else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
258
happened |= (POLLIN | POLLRDNORM) & sought;
260
/* Distinguish hung-up sockets from other errors. */
261
else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
262
|| socket_errno == ECONNABORTED || socket_errno == ENETRESET)
269
if (FD_ISSET (fd, wfds))
270
happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
272
if (FD_ISSET (fd, efds))
273
happened |= (POLLPRI | POLLRDBAND) & sought;
280
poll (pfd, nfd, timeout)
286
fd_set rfds, wfds, efds;
293
static int sc_open_max = -1;
296
|| (nfd > sc_open_max
297
&& (sc_open_max != -1
298
|| nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
303
#else /* !_SC_OPEN_MAX */
305
if (nfd < 0 || nfd > OPEN_MAX)
310
#endif /* OPEN_MAX -- else, no check is needed */
311
#endif /* !_SC_OPEN_MAX */
313
/* EFAULT is not necessary to implement, but let's do it in the
321
/* convert timeout number into a timeval structure */
328
else if (timeout > 0)
331
ptv->tv_sec = timeout / 1000;
332
ptv->tv_usec = (timeout % 1000) * 1000;
334
else if (timeout == INFTIM)
343
/* create fd sets and determine max fd */
348
for (i = 0; i < nfd; i++)
353
if (pfd[i].events & (POLLIN | POLLRDNORM))
354
FD_SET (pfd[i].fd, &rfds);
356
/* see select(2): "the only exceptional condition detectable
357
is out-of-band data received on a socket", hence we push
358
POLLWRBAND events onto wfds instead of efds. */
359
if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
360
FD_SET (pfd[i].fd, &wfds);
361
if (pfd[i].events & (POLLPRI | POLLRDBAND))
362
FD_SET (pfd[i].fd, &efds);
363
if (pfd[i].fd >= maxfd
364
&& (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
365
| POLLRDNORM | POLLRDBAND
366
| POLLWRNORM | POLLWRBAND)))
369
if (maxfd > FD_SETSIZE)
377
/* examine fd sets */
378
rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
382
/* establish results */
384
for (i = 0; i < nfd; i++)
389
int happened = compute_revents (pfd[i].fd, pfd[i].events,
390
&rfds, &wfds, &efds);
393
pfd[i].revents = happened;
400
static struct timeval tv0;
401
static HANDLE hEvent;
403
HANDLE h, handle_array[FD_SETSIZE + 2];
404
DWORD ret, wait_timeout, nhandles;
405
fd_set rfds, wfds, xfds;
418
hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
420
handle_array[0] = hEvent;
426
/* Classify socket handles and create fd sets. */
427
for (i = 0; i < nfd; i++)
432
if (!(pfd[i].events & (POLLIN | POLLRDNORM |
433
POLLOUT | POLLWRNORM | POLLWRBAND)))
436
h = (HANDLE) _get_osfhandle (pfd[i].fd);
439
/* Under Wine, it seems that getsockopt returns 0 for pipes too.
440
WSAEnumNetworkEvents instead distinguishes the two correctly. */
441
ev.lNetworkEvents = 0xDEADBEEF;
442
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
443
if (ev.lNetworkEvents != (long)0xDEADBEEF)
445
int requested = FD_CLOSE;
447
/* see above; socket handles are mapped onto select. */
448
if (pfd[i].events & (POLLIN | POLLRDNORM))
450
requested |= FD_READ | FD_ACCEPT;
451
FD_SET ((SOCKET) h, &rfds);
453
if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
455
requested |= FD_WRITE | FD_CONNECT;
456
FD_SET ((SOCKET) h, &wfds);
458
if (pfd[i].events & (POLLPRI | POLLRDBAND))
461
FD_SET ((SOCKET) h, &xfds);
465
WSAEventSelect ((SOCKET) h, hEvent, requested);
469
handle_array[nhandles++] = h;
471
/* Poll now. If we get an event, do not poll again. */
472
pfd[i].revents = win32_compute_revents (h, pfd[i].events);
478
if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
480
/* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
481
no need to call select again. */
488
if (timeout == INFTIM)
489
wait_timeout = INFINITE;
491
wait_timeout = timeout;
496
ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
497
wait_timeout, QS_ALLINPUT);
499
if (ret == WAIT_OBJECT_0 + nhandles)
501
/* new input of some other kind */
503
while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
505
TranslateMessage (&msg);
506
DispatchMessage (&msg);
514
select (0, &rfds, &wfds, &xfds, &tv0);
516
/* Place a sentinel at the end of the array. */
517
handle_array[nhandles] = NULL;
519
for (i = 0; i < nfd; i++)
525
if (!(pfd[i].events & (POLLIN | POLLRDNORM |
526
POLLOUT | POLLWRNORM | POLLWRBAND)))
529
h = (HANDLE) _get_osfhandle (pfd[i].fd);
530
if (h != handle_array[nhandles])
533
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
534
WSAEventSelect ((SOCKET) h, 0, 0);
536
/* If we're lucky, WSAEnumNetworkEvents already provided a way
537
to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
538
if (FD_ISSET ((SOCKET) h, &rfds)
539
&& !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
540
ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
541
if (FD_ISSET ((SOCKET) h, &wfds))
542
ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
543
if (FD_ISSET ((SOCKET) h, &xfds))
544
ev.lNetworkEvents |= FD_OOB;
546
happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
553
happened = win32_compute_revents (h, pfd[i].events);
556
if ((pfd[i].revents |= happened) != 0)