temporarily disable elisp exception tests
[bpt/guile.git] / lib / poll.c
CommitLineData
428f9e95
JE
1/* Emulation for poll(2)
2 Contributed by Paolo Bonzini.
3
5e69ceb7 4 Copyright 2001-2003, 2006-2014 Free Software Foundation, Inc.
428f9e95
JE
5
6 This file is part of gnulib.
7
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)
11 any later version.
12
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.
17
18 You should have received a copy of the GNU Lesser General Public License along
19 with this program; if not, see <http://www.gnu.org/licenses/>. */
20
21/* Tell gcc not to warn about the (nfd < 0) tests, below. */
22#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
23# pragma GCC diagnostic ignored "-Wtype-limits"
24#endif
25
26#include <config.h>
27#include <alloca.h>
28
29#include <sys/types.h>
30
31/* Specification. */
32#include <poll.h>
33
34#include <errno.h>
35#include <limits.h>
36#include <assert.h>
37
38#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
39# define WINDOWS_NATIVE
40# include <winsock2.h>
41# include <windows.h>
42# include <io.h>
43# include <stdio.h>
44# include <conio.h>
45# include "msvc-nothrow.h"
46#else
47# include <sys/time.h>
48# include <sys/socket.h>
49# include <sys/select.h>
50# include <unistd.h>
51#endif
52
53#ifdef HAVE_SYS_IOCTL_H
54# include <sys/ioctl.h>
55#endif
56#ifdef HAVE_SYS_FILIO_H
57# include <sys/filio.h>
58#endif
59
60#include <time.h>
61
62#ifndef INFTIM
63# define INFTIM (-1)
64#endif
65
66/* BeOS does not have MSG_PEEK. */
67#ifndef MSG_PEEK
68# define MSG_PEEK 0
69#endif
70
71#ifdef WINDOWS_NATIVE
72
73/* Optimized test whether a HANDLE refers to a console.
74 See <http://lists.gnu.org/archive/html/bug-gnulib/2009-08/msg00065.html>. */
75#define IsConsoleHandle(h) (((intptr_t) (h) & 3) == 3)
76
77static BOOL
78IsSocketHandle (HANDLE h)
79{
80 WSANETWORKEVENTS ev;
81
82 if (IsConsoleHandle (h))
83 return FALSE;
84
85 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
86 WSAEnumNetworkEvents instead distinguishes the two correctly. */
87 ev.lNetworkEvents = 0xDEADBEEF;
88 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
89 return ev.lNetworkEvents != 0xDEADBEEF;
90}
91
92/* Declare data structures for ntdll functions. */
93typedef struct _FILE_PIPE_LOCAL_INFORMATION {
94 ULONG NamedPipeType;
95 ULONG NamedPipeConfiguration;
96 ULONG MaximumInstances;
97 ULONG CurrentInstances;
98 ULONG InboundQuota;
99 ULONG ReadDataAvailable;
100 ULONG OutboundQuota;
101 ULONG WriteQuotaAvailable;
102 ULONG NamedPipeState;
103 ULONG NamedPipeEnd;
104} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
105
106typedef struct _IO_STATUS_BLOCK
107{
108 union {
109 DWORD Status;
110 PVOID Pointer;
111 } u;
112 ULONG_PTR Information;
113} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
114
115typedef enum _FILE_INFORMATION_CLASS {
116 FilePipeLocalInformation = 24
117} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
118
119typedef DWORD (WINAPI *PNtQueryInformationFile)
120 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
121
122# ifndef PIPE_BUF
123# define PIPE_BUF 512
124# endif
125
126/* Compute revents values for file handle H. If some events cannot happen
127 for the handle, eliminate them from *P_SOUGHT. */
128
129static int
130windows_compute_revents (HANDLE h, int *p_sought)
131{
132 int i, ret, happened;
133 INPUT_RECORD *irbuffer;
134 DWORD avail, nbuffer;
135 BOOL bRet;
136 IO_STATUS_BLOCK iosb;
137 FILE_PIPE_LOCAL_INFORMATION fpli;
138 static PNtQueryInformationFile NtQueryInformationFile;
139 static BOOL once_only;
140
141 switch (GetFileType (h))
142 {
143 case FILE_TYPE_PIPE:
144 if (!once_only)
145 {
146 NtQueryInformationFile = (PNtQueryInformationFile)
147 GetProcAddress (GetModuleHandle ("ntdll.dll"),
148 "NtQueryInformationFile");
149 once_only = TRUE;
150 }
151
152 happened = 0;
153 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
154 {
155 if (avail)
156 happened |= *p_sought & (POLLIN | POLLRDNORM);
157 }
158 else if (GetLastError () == ERROR_BROKEN_PIPE)
159 happened |= POLLHUP;
160
161 else
162 {
163 /* It was the write-end of the pipe. Check if it is writable.
164 If NtQueryInformationFile fails, optimistically assume the pipe is
165 writable. This could happen on Windows 9x, where
166 NtQueryInformationFile is not available, or if we inherit a pipe
167 that doesn't permit FILE_READ_ATTRIBUTES access on the write end
168 (I think this should not happen since Windows XP SP2; WINE seems
169 fine too). Otherwise, ensure that enough space is available for
170 atomic writes. */
171 memset (&iosb, 0, sizeof (iosb));
172 memset (&fpli, 0, sizeof (fpli));
173
174 if (!NtQueryInformationFile
175 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
176 FilePipeLocalInformation)
177 || fpli.WriteQuotaAvailable >= PIPE_BUF
178 || (fpli.OutboundQuota < PIPE_BUF &&
179 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
180 happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
181 }
182 return happened;
183
184 case FILE_TYPE_CHAR:
185 ret = WaitForSingleObject (h, 0);
186 if (!IsConsoleHandle (h))
187 return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
188
189 nbuffer = avail = 0;
190 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
191 if (bRet)
192 {
193 /* Input buffer. */
194 *p_sought &= POLLIN | POLLRDNORM;
195 if (nbuffer == 0)
196 return POLLHUP;
197 if (!*p_sought)
198 return 0;
199
200 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
201 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
202 if (!bRet || avail == 0)
203 return POLLHUP;
204
205 for (i = 0; i < avail; i++)
206 if (irbuffer[i].EventType == KEY_EVENT)
207 return *p_sought;
208 return 0;
209 }
210 else
211 {
212 /* Screen buffer. */
213 *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
214 return *p_sought;
215 }
216
217 default:
218 ret = WaitForSingleObject (h, 0);
219 if (ret == WAIT_OBJECT_0)
220 return *p_sought & ~(POLLPRI | POLLRDBAND);
221
222 return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
223 }
224}
225
226/* Convert fd_sets returned by select into revents values. */
227
228static int
229windows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
230{
231 int happened = 0;
232
233 if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
234 happened |= (POLLIN | POLLRDNORM) & sought;
235
236 else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
237 {
238 int r, error;
239
240 char data[64];
241 WSASetLastError (0);
242 r = recv (h, data, sizeof (data), MSG_PEEK);
243 error = WSAGetLastError ();
244 WSASetLastError (0);
245
246 if (r > 0 || error == WSAENOTCONN)
247 happened |= (POLLIN | POLLRDNORM) & sought;
248
249 /* Distinguish hung-up sockets from other errors. */
250 else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
251 || error == WSAECONNABORTED || error == WSAENETRESET)
252 happened |= POLLHUP;
253
254 else
255 happened |= POLLERR;
256 }
257
258 if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
259 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
260
261 if (lNetworkEvents & FD_OOB)
262 happened |= (POLLPRI | POLLRDBAND) & sought;
263
264 return happened;
265}
266
267#else /* !MinGW */
268
269/* Convert select(2) returned fd_sets into poll(2) revents values. */
270static int
271compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
272{
273 int happened = 0;
274 if (FD_ISSET (fd, rfds))
275 {
276 int r;
277 int socket_errno;
278
279# if defined __MACH__ && defined __APPLE__
280 /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
281 for some kinds of descriptors. Detect if this descriptor is a
282 connected socket, a server socket, or something else using a
283 0-byte recv, and use ioctl(2) to detect POLLHUP. */
284 r = recv (fd, NULL, 0, MSG_PEEK);
285 socket_errno = (r < 0) ? errno : 0;
286 if (r == 0 || socket_errno == ENOTSOCK)
287 ioctl (fd, FIONREAD, &r);
288# else
289 char data[64];
290 r = recv (fd, data, sizeof (data), MSG_PEEK);
291 socket_errno = (r < 0) ? errno : 0;
292# endif
293 if (r == 0)
294 happened |= POLLHUP;
295
296 /* If the event happened on an unconnected server socket,
297 that's fine. */
298 else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
299 happened |= (POLLIN | POLLRDNORM) & sought;
300
301 /* Distinguish hung-up sockets from other errors. */
302 else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
303 || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
304 happened |= POLLHUP;
305
306 /* some systems can't use recv() on non-socket, including HP NonStop */
307 else if (socket_errno == ENOTSOCK)
308 happened |= (POLLIN | POLLRDNORM) & sought;
309
310 else
311 happened |= POLLERR;
312 }
313
314 if (FD_ISSET (fd, wfds))
315 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
316
317 if (FD_ISSET (fd, efds))
318 happened |= (POLLPRI | POLLRDBAND) & sought;
319
320 return happened;
321}
322#endif /* !MinGW */
323
324int
325poll (struct pollfd *pfd, nfds_t nfd, int timeout)
326{
327#ifndef WINDOWS_NATIVE
328 fd_set rfds, wfds, efds;
329 struct timeval tv;
330 struct timeval *ptv;
331 int maxfd, rc;
332 nfds_t i;
333
334# ifdef _SC_OPEN_MAX
335 static int sc_open_max = -1;
336
337 if (nfd < 0
338 || (nfd > sc_open_max
339 && (sc_open_max != -1
340 || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
341 {
342 errno = EINVAL;
343 return -1;
344 }
345# else /* !_SC_OPEN_MAX */
346# ifdef OPEN_MAX
347 if (nfd < 0 || nfd > OPEN_MAX)
348 {
349 errno = EINVAL;
350 return -1;
351 }
352# endif /* OPEN_MAX -- else, no check is needed */
353# endif /* !_SC_OPEN_MAX */
354
355 /* EFAULT is not necessary to implement, but let's do it in the
356 simplest case. */
357 if (!pfd && nfd)
358 {
359 errno = EFAULT;
360 return -1;
361 }
362
363 /* convert timeout number into a timeval structure */
364 if (timeout == 0)
365 {
366 ptv = &tv;
367 ptv->tv_sec = 0;
368 ptv->tv_usec = 0;
369 }
370 else if (timeout > 0)
371 {
372 ptv = &tv;
373 ptv->tv_sec = timeout / 1000;
374 ptv->tv_usec = (timeout % 1000) * 1000;
375 }
376 else if (timeout == INFTIM)
377 /* wait forever */
378 ptv = NULL;
379 else
380 {
381 errno = EINVAL;
382 return -1;
383 }
384
385 /* create fd sets and determine max fd */
386 maxfd = -1;
387 FD_ZERO (&rfds);
388 FD_ZERO (&wfds);
389 FD_ZERO (&efds);
390 for (i = 0; i < nfd; i++)
391 {
392 if (pfd[i].fd < 0)
393 continue;
394
395 if (pfd[i].events & (POLLIN | POLLRDNORM))
396 FD_SET (pfd[i].fd, &rfds);
397
398 /* see select(2): "the only exceptional condition detectable
399 is out-of-band data received on a socket", hence we push
400 POLLWRBAND events onto wfds instead of efds. */
401 if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
402 FD_SET (pfd[i].fd, &wfds);
403 if (pfd[i].events & (POLLPRI | POLLRDBAND))
404 FD_SET (pfd[i].fd, &efds);
405 if (pfd[i].fd >= maxfd
406 && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
407 | POLLRDNORM | POLLRDBAND
408 | POLLWRNORM | POLLWRBAND)))
409 {
410 maxfd = pfd[i].fd;
411 if (maxfd > FD_SETSIZE)
412 {
413 errno = EOVERFLOW;
414 return -1;
415 }
416 }
417 }
418
419 /* examine fd sets */
420 rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
421 if (rc < 0)
422 return rc;
423
424 /* establish results */
425 rc = 0;
426 for (i = 0; i < nfd; i++)
427 if (pfd[i].fd < 0)
428 pfd[i].revents = 0;
429 else
430 {
431 int happened = compute_revents (pfd[i].fd, pfd[i].events,
432 &rfds, &wfds, &efds);
433 if (happened)
434 {
435 pfd[i].revents = happened;
436 rc++;
437 }
438 }
439
440 return rc;
441#else
442 static struct timeval tv0;
443 static HANDLE hEvent;
444 WSANETWORKEVENTS ev;
445 HANDLE h, handle_array[FD_SETSIZE + 2];
446 DWORD ret, wait_timeout, nhandles;
447 fd_set rfds, wfds, xfds;
448 BOOL poll_again;
449 MSG msg;
450 int rc = 0;
451 nfds_t i;
452
453 if (nfd < 0 || timeout < -1)
454 {
455 errno = EINVAL;
456 return -1;
457 }
458
459 if (!hEvent)
460 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
461
462restart:
463 handle_array[0] = hEvent;
464 nhandles = 1;
465 FD_ZERO (&rfds);
466 FD_ZERO (&wfds);
467 FD_ZERO (&xfds);
468
469 /* Classify socket handles and create fd sets. */
470 for (i = 0; i < nfd; i++)
471 {
472 int sought = pfd[i].events;
473 pfd[i].revents = 0;
474 if (pfd[i].fd < 0)
475 continue;
476 if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
477 | POLLPRI | POLLRDBAND)))
478 continue;
479
480 h = (HANDLE) _get_osfhandle (pfd[i].fd);
481 assert (h != NULL);
482 if (IsSocketHandle (h))
483 {
484 int requested = FD_CLOSE;
485
486 /* see above; socket handles are mapped onto select. */
487 if (sought & (POLLIN | POLLRDNORM))
488 {
489 requested |= FD_READ | FD_ACCEPT;
490 FD_SET ((SOCKET) h, &rfds);
491 }
492 if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
493 {
494 requested |= FD_WRITE | FD_CONNECT;
495 FD_SET ((SOCKET) h, &wfds);
496 }
497 if (sought & (POLLPRI | POLLRDBAND))
498 {
499 requested |= FD_OOB;
500 FD_SET ((SOCKET) h, &xfds);
501 }
502
503 if (requested)
504 WSAEventSelect ((SOCKET) h, hEvent, requested);
505 }
506 else
507 {
508 /* Poll now. If we get an event, do not poll again. Also,
509 screen buffer handles are waitable, and they'll block until
510 a character is available. windows_compute_revents eliminates
511 bits for the "wrong" direction. */
512 pfd[i].revents = windows_compute_revents (h, &sought);
513 if (sought)
514 handle_array[nhandles++] = h;
515 if (pfd[i].revents)
516 timeout = 0;
517 }
518 }
519
520 if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
521 {
522 /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
523 no need to call select again. */
524 poll_again = FALSE;
525 wait_timeout = 0;
526 }
527 else
528 {
529 poll_again = TRUE;
530 if (timeout == INFTIM)
531 wait_timeout = INFINITE;
532 else
533 wait_timeout = timeout;
534 }
535
536 for (;;)
537 {
538 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
539 wait_timeout, QS_ALLINPUT);
540
541 if (ret == WAIT_OBJECT_0 + nhandles)
542 {
543 /* new input of some other kind */
544 BOOL bRet;
545 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
546 {
547 TranslateMessage (&msg);
548 DispatchMessage (&msg);
549 }
550 }
551 else
552 break;
553 }
554
555 if (poll_again)
556 select (0, &rfds, &wfds, &xfds, &tv0);
557
558 /* Place a sentinel at the end of the array. */
559 handle_array[nhandles] = NULL;
560 nhandles = 1;
561 for (i = 0; i < nfd; i++)
562 {
563 int happened;
564
565 if (pfd[i].fd < 0)
566 continue;
567 if (!(pfd[i].events & (POLLIN | POLLRDNORM |
568 POLLOUT | POLLWRNORM | POLLWRBAND)))
569 continue;
570
571 h = (HANDLE) _get_osfhandle (pfd[i].fd);
572 if (h != handle_array[nhandles])
573 {
574 /* It's a socket. */
575 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
576 WSAEventSelect ((SOCKET) h, 0, 0);
577
578 /* If we're lucky, WSAEnumNetworkEvents already provided a way
579 to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
580 if (FD_ISSET ((SOCKET) h, &rfds)
581 && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
582 ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
583 if (FD_ISSET ((SOCKET) h, &wfds))
584 ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
585 if (FD_ISSET ((SOCKET) h, &xfds))
586 ev.lNetworkEvents |= FD_OOB;
587
588 happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events,
589 ev.lNetworkEvents);
590 }
591 else
592 {
593 /* Not a socket. */
594 int sought = pfd[i].events;
595 happened = windows_compute_revents (h, &sought);
596 nhandles++;
597 }
598
599 if ((pfd[i].revents |= happened) != 0)
600 rc++;
601 }
602
603 if (!rc && timeout == INFTIM)
604 {
605 SleepEx (1, TRUE);
606 goto restart;
607 }
608
609 return rc;
610#endif
611}