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 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. */
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)
104 int i, ret, happened;
105 INPUT_RECORD *irbuffer;
106 DWORD avail, nbuffer;
108 IO_STATUS_BLOCK iosb;
109 FILE_PIPE_LOCAL_INFORMATION fpli;
110 static PNtQueryInformationFile NtQueryInformationFile;
111 static BOOL once_only;
113 switch (GetFileType (h))
118 NtQueryInformationFile = (PNtQueryInformationFile)
119 GetProcAddress (GetModuleHandle ("ntdll.dll"),
120 "NtQueryInformationFile");
125 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
128 happened |= sought & (POLLIN | POLLRDNORM);
133 /* It was the write-end of the pipe. Check if it is writable.
134 If NtQueryInformationFile fails, optimistically assume the pipe is
135 writable. This could happen on Win9x, where NtQueryInformationFile
136 is not available, or if we inherit a pipe that doesn't permit
137 FILE_READ_ATTRIBUTES access on the write end (I think this should
138 not happen since WinXP SP2; WINE seems fine too). Otherwise,
139 ensure that enough space is available for atomic writes. */
140 memset (&iosb, 0, sizeof (iosb));
141 memset (&fpli, 0, sizeof (fpli));
143 if (!NtQueryInformationFile
144 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
145 FilePipeLocalInformation)
146 || fpli.WriteQuotaAvailable >= PIPE_BUF
147 || (fpli.OutboundQuota < PIPE_BUF &&
148 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
149 happened |= sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
154 ret = WaitForSingleObject (h, 0);
155 if (ret == WAIT_OBJECT_0)
158 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
159 if (!bRet || nbuffer == 0)
162 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
163 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
164 if (!bRet || avail == 0)
167 for (i = 0; i < avail; i++)
168 if (irbuffer[i].EventType == KEY_EVENT)
169 return sought & ~(POLLPRI | POLLRDBAND);
174 ret = WaitForSingleObject (h, 0);
175 if (ret == WAIT_OBJECT_0)
176 return sought & ~(POLLPRI | POLLRDBAND);
181 return sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
184 /* Convert fd_sets returned by select into revents values. */
187 win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
191 if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
192 happened |= (POLLIN | POLLRDNORM) & sought;
194 else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
200 r = recv (h, data, sizeof (data), MSG_PEEK);
201 error = WSAGetLastError ();
204 if (r > 0 || error == WSAENOTCONN)
205 happened |= (POLLIN | POLLRDNORM) & sought;
207 /* Distinguish hung-up sockets from other errors. */
208 else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
209 || error == WSAECONNABORTED || error == WSAENETRESET)
216 if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
217 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
219 if (lNetworkEvents & FD_OOB)
220 happened |= (POLLPRI | POLLRDBAND) & sought;
227 /* Convert select(2) returned fd_sets into poll(2) revents values. */
229 compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
232 if (FD_ISSET (fd, rfds))
237 #if defined __MACH__ && defined __APPLE__
238 /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
239 for some kinds of descriptors. Detect if this descriptor is a
240 connected socket, a server socket, or something else using a
241 0-byte recv, and use ioctl(2) to detect POLLHUP. */
242 r = recv (fd, NULL, 0, MSG_PEEK);
243 socket_errno = (r < 0) ? errno : 0;
244 if (r == 0 || socket_errno == ENOTSOCK)
245 ioctl (fd, FIONREAD, &r);
248 r = recv (fd, data, sizeof (data), MSG_PEEK);
249 socket_errno = (r < 0) ? errno : 0;
254 /* If the event happened on an unconnected server socket,
256 else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
257 happened |= (POLLIN | POLLRDNORM) & sought;
259 /* Distinguish hung-up sockets from other errors. */
260 else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
261 || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
268 if (FD_ISSET (fd, wfds))
269 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
271 if (FD_ISSET (fd, efds))
272 happened |= (POLLPRI | POLLRDBAND) & sought;
279 poll (pfd, nfd, timeout)
285 fd_set rfds, wfds, efds;
292 static int sc_open_max = -1;
295 || (nfd > sc_open_max
296 && (sc_open_max != -1
297 || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
302 #else /* !_SC_OPEN_MAX */
304 if (nfd < 0 || nfd > OPEN_MAX)
309 #endif /* OPEN_MAX -- else, no check is needed */
310 #endif /* !_SC_OPEN_MAX */
312 /* EFAULT is not necessary to implement, but let's do it in the
320 /* convert timeout number into a timeval structure */
327 else if (timeout > 0)
330 ptv->tv_sec = timeout / 1000;
331 ptv->tv_usec = (timeout % 1000) * 1000;
333 else if (timeout == INFTIM)
342 /* create fd sets and determine max fd */
347 for (i = 0; i < nfd; i++)
352 if (pfd[i].events & (POLLIN | POLLRDNORM))
353 FD_SET (pfd[i].fd, &rfds);
355 /* see select(2): "the only exceptional condition detectable
356 is out-of-band data received on a socket", hence we push
357 POLLWRBAND events onto wfds instead of efds. */
358 if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
359 FD_SET (pfd[i].fd, &wfds);
360 if (pfd[i].events & (POLLPRI | POLLRDBAND))
361 FD_SET (pfd[i].fd, &efds);
362 if (pfd[i].fd >= maxfd
363 && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
364 | POLLRDNORM | POLLRDBAND
365 | POLLWRNORM | POLLWRBAND)))
368 if (maxfd > FD_SETSIZE)
376 /* examine fd sets */
377 rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
381 /* establish results */
383 for (i = 0; i < nfd; i++)
388 int happened = compute_revents (pfd[i].fd, pfd[i].events,
389 &rfds, &wfds, &efds);
392 pfd[i].revents = happened;
399 static struct timeval tv0;
400 static HANDLE hEvent;
402 HANDLE h, handle_array[FD_SETSIZE + 2];
403 DWORD ret, wait_timeout, nhandles;
404 fd_set rfds, wfds, xfds;
411 if (nfd < 0 || timeout < -1)
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++)
429 size_t optlen = sizeof(sockbuf);
433 if (!(pfd[i].events & (POLLIN | POLLRDNORM |
434 POLLOUT | POLLWRNORM | POLLWRBAND)))
437 h = (HANDLE) _get_osfhandle (pfd[i].fd);
440 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
441 WSAEnumNetworkEvents instead distinguishes the two correctly. */
442 ev.lNetworkEvents = 0xDEADBEEF;
443 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
444 if (ev.lNetworkEvents != 0xDEADBEEF)
446 int requested = FD_CLOSE;
448 /* see above; socket handles are mapped onto select. */
449 if (pfd[i].events & (POLLIN | POLLRDNORM))
451 requested |= FD_READ | FD_ACCEPT;
452 FD_SET ((SOCKET) h, &rfds);
454 if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
456 requested |= FD_WRITE | FD_CONNECT;
457 FD_SET ((SOCKET) h, &wfds);
459 if (pfd[i].events & (POLLPRI | POLLRDBAND))
462 FD_SET ((SOCKET) h, &xfds);
466 WSAEventSelect ((SOCKET) h, hEvent, requested);
470 handle_array[nhandles++] = h;
472 /* Poll now. If we get an event, do not poll again. */
473 pfd[i].revents = win32_compute_revents (h, pfd[i].events);
479 if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
481 /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
482 no need to call select again. */
489 if (timeout == INFTIM)
490 wait_timeout = INFINITE;
492 wait_timeout = timeout;
497 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
498 wait_timeout, QS_ALLINPUT);
500 if (ret == WAIT_OBJECT_0 + nhandles)
502 /* new input of some other kind */
504 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
506 TranslateMessage (&msg);
507 DispatchMessage (&msg);
515 select (0, &rfds, &wfds, &xfds, &tv0);
517 /* Place a sentinel at the end of the array. */
518 handle_array[nhandles] = NULL;
520 for (i = 0; i < nfd; i++)
526 if (!(pfd[i].events & (POLLIN | POLLRDNORM |
527 POLLOUT | POLLWRNORM | POLLWRBAND)))
530 h = (HANDLE) _get_osfhandle (pfd[i].fd);
531 if (h != handle_array[nhandles])
534 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
535 WSAEventSelect ((SOCKET) h, 0, 0);
537 /* If we're lucky, WSAEnumNetworkEvents already provided a way
538 to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
539 if (FD_ISSET ((SOCKET) h, &rfds)
540 && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
541 ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
542 if (FD_ISSET ((SOCKET) h, &wfds))
543 ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
544 if (FD_ISSET ((SOCKET) h, &xfds))
545 ev.lNetworkEvents |= FD_OOB;
547 happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
554 happened = win32_compute_revents (h, pfd[i].events);
557 if ((pfd[i].revents |= happened) != 0)