mingw: use poll-emulation from gnulib
[git/dscho.git] / compat / win32 / sys / poll.c
blob7e74ebe59a5ea2e31a9100659805ada0f5d8e278
1 /* Emulation for poll(2)
2 Contributed by Paolo Bonzini.
4 Copyright 2001-2003, 2006-2010 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)
11 any later version.
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. */
22 /* Tell gcc not to warn about the (nfd < 0) tests, below. */
23 #if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
24 # pragma GCC diagnostic ignored "-Wtype-limits"
25 #endif
27 #include <malloc.h>
29 #include <sys/types.h>
30 #include "poll.h"
31 #include <errno.h>
32 #include <limits.h>
33 #include <assert.h>
35 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
36 # define WIN32_NATIVE
37 # include <winsock2.h>
38 # include <windows.h>
39 # include <io.h>
40 # include <stdio.h>
41 # include <conio.h>
42 #else
43 # include <sys/time.h>
44 # include <sys/socket.h>
45 # include <sys/select.h>
46 # include <unistd.h>
47 #endif
49 #ifdef HAVE_SYS_IOCTL_H
50 # include <sys/ioctl.h>
51 #endif
52 #ifdef HAVE_SYS_FILIO_H
53 # include <sys/filio.h>
54 #endif
56 #include <time.h>
58 #ifndef INFTIM
59 # define INFTIM (-1)
60 #endif
62 /* BeOS does not have MSG_PEEK. */
63 #ifndef MSG_PEEK
64 # define MSG_PEEK 0
65 #endif
67 #ifdef WIN32_NATIVE
69 #define IsConsoleHandle(h) (((long) (h) & 3) == 3)
71 static BOOL
72 IsSocketHandle (HANDLE h)
74 WSANETWORKEVENTS ev;
76 if (IsConsoleHandle (h))
77 return FALSE;
79 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
80 WSAEnumNetworkEvents instead distinguishes the two correctly. */
81 ev.lNetworkEvents = 0xDEADBEEF;
82 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
83 return ev.lNetworkEvents != 0xDEADBEEF;
86 /* Declare data structures for ntdll functions. */
87 typedef struct _FILE_PIPE_LOCAL_INFORMATION {
88 ULONG NamedPipeType;
89 ULONG NamedPipeConfiguration;
90 ULONG MaximumInstances;
91 ULONG CurrentInstances;
92 ULONG InboundQuota;
93 ULONG ReadDataAvailable;
94 ULONG OutboundQuota;
95 ULONG WriteQuotaAvailable;
96 ULONG NamedPipeState;
97 ULONG NamedPipeEnd;
98 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
100 typedef struct _IO_STATUS_BLOCK
102 union {
103 DWORD Status;
104 PVOID Pointer;
105 } u;
106 ULONG_PTR Information;
107 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
109 typedef enum _FILE_INFORMATION_CLASS {
110 FilePipeLocalInformation = 24
111 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
113 typedef DWORD (WINAPI *PNtQueryInformationFile)
114 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
116 # ifndef PIPE_BUF
117 # define PIPE_BUF 512
118 # endif
120 /* Compute revents values for file handle H. If some events cannot happen
121 for the handle, eliminate them from *P_SOUGHT. */
123 static int
124 win32_compute_revents (HANDLE h, int *p_sought)
126 int i, ret, happened;
127 INPUT_RECORD *irbuffer;
128 DWORD avail, nbuffer;
129 BOOL bRet;
130 IO_STATUS_BLOCK iosb;
131 FILE_PIPE_LOCAL_INFORMATION fpli;
132 static PNtQueryInformationFile NtQueryInformationFile;
133 static BOOL once_only;
135 switch (GetFileType (h))
137 case FILE_TYPE_PIPE:
138 if (!once_only)
140 NtQueryInformationFile = (PNtQueryInformationFile)
141 GetProcAddress (GetModuleHandle ("ntdll.dll"),
142 "NtQueryInformationFile");
143 once_only = TRUE;
146 happened = 0;
147 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
149 if (avail)
150 happened |= *p_sought & (POLLIN | POLLRDNORM);
152 else if (GetLastError () == ERROR_BROKEN_PIPE)
153 happened |= POLLHUP;
155 else
157 /* It was the write-end of the pipe. Check if it is writable.
158 If NtQueryInformationFile fails, optimistically assume the pipe is
159 writable. This could happen on Win9x, where NtQueryInformationFile
160 is not available, or if we inherit a pipe that doesn't permit
161 FILE_READ_ATTRIBUTES access on the write end (I think this should
162 not happen since WinXP SP2; WINE seems fine too). Otherwise,
163 ensure that enough space is available for atomic writes. */
164 memset (&iosb, 0, sizeof (iosb));
165 memset (&fpli, 0, sizeof (fpli));
167 if (!NtQueryInformationFile
168 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
169 FilePipeLocalInformation)
170 || fpli.WriteQuotaAvailable >= PIPE_BUF
171 || (fpli.OutboundQuota < PIPE_BUF &&
172 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
173 happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
175 return happened;
177 case FILE_TYPE_CHAR:
178 ret = WaitForSingleObject (h, 0);
179 if (!IsConsoleHandle (h))
180 return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
182 nbuffer = avail = 0;
183 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
184 if (bRet)
186 /* Input buffer. */
187 *p_sought &= POLLIN | POLLRDNORM;
188 if (nbuffer == 0)
189 return POLLHUP;
190 if (!*p_sought)
191 return 0;
193 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
194 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
195 if (!bRet || avail == 0)
196 return POLLHUP;
198 for (i = 0; i < avail; i++)
199 if (irbuffer[i].EventType == KEY_EVENT)
200 return *p_sought;
201 return 0;
203 else
205 /* Screen buffer. */
206 *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
207 return *p_sought;
210 default:
211 ret = WaitForSingleObject (h, 0);
212 if (ret == WAIT_OBJECT_0)
213 return *p_sought & ~(POLLPRI | POLLRDBAND);
215 return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
219 /* Convert fd_sets returned by select into revents values. */
221 static int
222 win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
224 int happened = 0;
226 if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
227 happened |= (POLLIN | POLLRDNORM) & sought;
229 else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
231 int r, error;
233 char data[64];
234 WSASetLastError (0);
235 r = recv (h, data, sizeof (data), MSG_PEEK);
236 error = WSAGetLastError ();
237 WSASetLastError (0);
239 if (r > 0 || error == WSAENOTCONN)
240 happened |= (POLLIN | POLLRDNORM) & sought;
242 /* Distinguish hung-up sockets from other errors. */
243 else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
244 || error == WSAECONNABORTED || error == WSAENETRESET)
245 happened |= POLLHUP;
247 else
248 happened |= POLLERR;
251 if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
252 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
254 if (lNetworkEvents & FD_OOB)
255 happened |= (POLLPRI | POLLRDBAND) & sought;
257 return happened;
260 #else /* !MinGW */
262 /* Convert select(2) returned fd_sets into poll(2) revents values. */
263 static int
264 compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
266 int happened = 0;
267 if (FD_ISSET (fd, rfds))
269 int r;
270 int socket_errno;
272 # if defined __MACH__ && defined __APPLE__
273 /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
274 for some kinds of descriptors. Detect if this descriptor is a
275 connected socket, a server socket, or something else using a
276 0-byte recv, and use ioctl(2) to detect POLLHUP. */
277 r = recv (fd, NULL, 0, MSG_PEEK);
278 socket_errno = (r < 0) ? errno : 0;
279 if (r == 0 || socket_errno == ENOTSOCK)
280 ioctl (fd, FIONREAD, &r);
281 # else
282 char data[64];
283 r = recv (fd, data, sizeof (data), MSG_PEEK);
284 socket_errno = (r < 0) ? errno : 0;
285 # endif
286 if (r == 0)
287 happened |= POLLHUP;
289 /* If the event happened on an unconnected server socket,
290 that's fine. */
291 else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
292 happened |= (POLLIN | POLLRDNORM) & sought;
294 /* Distinguish hung-up sockets from other errors. */
295 else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
296 || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
297 happened |= POLLHUP;
299 else
300 happened |= POLLERR;
303 if (FD_ISSET (fd, wfds))
304 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
306 if (FD_ISSET (fd, efds))
307 happened |= (POLLPRI | POLLRDBAND) & sought;
309 return happened;
311 #endif /* !MinGW */
314 poll (pfd, nfd, timeout)
315 struct pollfd *pfd;
316 nfds_t nfd;
317 int timeout;
319 #ifndef WIN32_NATIVE
320 fd_set rfds, wfds, efds;
321 struct timeval tv;
322 struct timeval *ptv;
323 int maxfd, rc;
324 nfds_t i;
326 # ifdef _SC_OPEN_MAX
327 static int sc_open_max = -1;
329 if (nfd < 0
330 || (nfd > sc_open_max
331 && (sc_open_max != -1
332 || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
334 errno = EINVAL;
335 return -1;
337 # else /* !_SC_OPEN_MAX */
338 # ifdef OPEN_MAX
339 if (nfd < 0 || nfd > OPEN_MAX)
341 errno = EINVAL;
342 return -1;
344 # endif /* OPEN_MAX -- else, no check is needed */
345 # endif /* !_SC_OPEN_MAX */
347 /* EFAULT is not necessary to implement, but let's do it in the
348 simplest case. */
349 if (!pfd)
351 errno = EFAULT;
352 return -1;
355 /* convert timeout number into a timeval structure */
356 if (timeout == 0)
358 ptv = &tv;
359 ptv->tv_sec = 0;
360 ptv->tv_usec = 0;
362 else if (timeout > 0)
364 ptv = &tv;
365 ptv->tv_sec = timeout / 1000;
366 ptv->tv_usec = (timeout % 1000) * 1000;
368 else if (timeout == INFTIM)
369 /* wait forever */
370 ptv = NULL;
371 else
373 errno = EINVAL;
374 return -1;
377 /* create fd sets and determine max fd */
378 maxfd = -1;
379 FD_ZERO (&rfds);
380 FD_ZERO (&wfds);
381 FD_ZERO (&efds);
382 for (i = 0; i < nfd; i++)
384 if (pfd[i].fd < 0)
385 continue;
387 if (pfd[i].events & (POLLIN | POLLRDNORM))
388 FD_SET (pfd[i].fd, &rfds);
390 /* see select(2): "the only exceptional condition detectable
391 is out-of-band data received on a socket", hence we push
392 POLLWRBAND events onto wfds instead of efds. */
393 if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
394 FD_SET (pfd[i].fd, &wfds);
395 if (pfd[i].events & (POLLPRI | POLLRDBAND))
396 FD_SET (pfd[i].fd, &efds);
397 if (pfd[i].fd >= maxfd
398 && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
399 | POLLRDNORM | POLLRDBAND
400 | POLLWRNORM | POLLWRBAND)))
402 maxfd = pfd[i].fd;
403 if (maxfd > FD_SETSIZE)
405 errno = EOVERFLOW;
406 return -1;
411 /* examine fd sets */
412 rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
413 if (rc < 0)
414 return rc;
416 /* establish results */
417 rc = 0;
418 for (i = 0; i < nfd; i++)
419 if (pfd[i].fd < 0)
420 pfd[i].revents = 0;
421 else
423 int happened = compute_revents (pfd[i].fd, pfd[i].events,
424 &rfds, &wfds, &efds);
425 if (happened)
427 pfd[i].revents = happened;
428 rc++;
432 return rc;
433 #else
434 static struct timeval tv0;
435 static HANDLE hEvent;
436 WSANETWORKEVENTS ev;
437 HANDLE h, handle_array[FD_SETSIZE + 2];
438 DWORD ret, wait_timeout, nhandles;
439 fd_set rfds, wfds, xfds;
440 BOOL poll_again;
441 MSG msg;
442 int rc = 0;
443 nfds_t i;
445 if (nfd < 0 || timeout < -1)
447 errno = EINVAL;
448 return -1;
451 if (!hEvent)
452 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
454 handle_array[0] = hEvent;
455 nhandles = 1;
456 FD_ZERO (&rfds);
457 FD_ZERO (&wfds);
458 FD_ZERO (&xfds);
460 /* Classify socket handles and create fd sets. */
461 for (i = 0; i < nfd; i++)
463 int sought = pfd[i].events;
464 pfd[i].revents = 0;
465 if (pfd[i].fd < 0)
466 continue;
467 if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
468 | POLLPRI | POLLRDBAND)))
469 continue;
471 h = (HANDLE) _get_osfhandle (pfd[i].fd);
472 assert (h != NULL);
473 if (IsSocketHandle (h))
475 int requested = FD_CLOSE;
477 /* see above; socket handles are mapped onto select. */
478 if (sought & (POLLIN | POLLRDNORM))
480 requested |= FD_READ | FD_ACCEPT;
481 FD_SET ((SOCKET) h, &rfds);
483 if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
485 requested |= FD_WRITE | FD_CONNECT;
486 FD_SET ((SOCKET) h, &wfds);
488 if (sought & (POLLPRI | POLLRDBAND))
490 requested |= FD_OOB;
491 FD_SET ((SOCKET) h, &xfds);
494 if (requested)
495 WSAEventSelect ((SOCKET) h, hEvent, requested);
497 else
499 /* Poll now. If we get an event, do not poll again. Also,
500 screen buffer handles are waitable, and they'll block until
501 a character is available. win32_compute_revents eliminates
502 bits for the "wrong" direction. */
503 pfd[i].revents = win32_compute_revents (h, &sought);
504 if (sought)
505 handle_array[nhandles++] = h;
506 if (pfd[i].revents)
507 timeout = 0;
511 if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
513 /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
514 no need to call select again. */
515 poll_again = FALSE;
516 wait_timeout = 0;
518 else
520 poll_again = TRUE;
521 if (timeout == INFTIM)
522 wait_timeout = INFINITE;
523 else
524 wait_timeout = timeout;
527 for (;;)
529 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
530 wait_timeout, QS_ALLINPUT);
532 if (ret == WAIT_OBJECT_0 + nhandles)
534 /* new input of some other kind */
535 BOOL bRet;
536 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
538 TranslateMessage (&msg);
539 DispatchMessage (&msg);
542 else
543 break;
546 if (poll_again)
547 select (0, &rfds, &wfds, &xfds, &tv0);
549 /* Place a sentinel at the end of the array. */
550 handle_array[nhandles] = NULL;
551 nhandles = 1;
552 for (i = 0; i < nfd; i++)
554 int happened;
556 if (pfd[i].fd < 0)
557 continue;
558 if (!(pfd[i].events & (POLLIN | POLLRDNORM |
559 POLLOUT | POLLWRNORM | POLLWRBAND)))
560 continue;
562 h = (HANDLE) _get_osfhandle (pfd[i].fd);
563 if (h != handle_array[nhandles])
565 /* It's a socket. */
566 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
567 WSAEventSelect ((SOCKET) h, 0, 0);
569 /* If we're lucky, WSAEnumNetworkEvents already provided a way
570 to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
571 if (FD_ISSET ((SOCKET) h, &rfds)
572 && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
573 ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
574 if (FD_ISSET ((SOCKET) h, &wfds))
575 ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
576 if (FD_ISSET ((SOCKET) h, &xfds))
577 ev.lNetworkEvents |= FD_OOB;
579 happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
580 ev.lNetworkEvents);
582 else
584 /* Not a socket. */
585 int sought = pfd[i].events;
586 happened = win32_compute_revents (h, &sought);
587 nhandles++;
590 if ((pfd[i].revents |= happened) != 0)
591 rc++;
594 return rc;
595 #endif