exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / poll.c
blob37cb2d7ba4481e5bd72b5dcb4f446a84518f1926
1 /* Emulation for poll(2)
2 Contributed by Paolo Bonzini.
4 Copyright 2001-2003, 2006-2024 Free Software Foundation, Inc.
6 This file is part of gnulib.
8 This file is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation; either version 2.1 of the
11 License, or (at your option) any later version.
13 This file 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
19 along with this program. If not, see <https://www.gnu.org/licenses/>. */
21 #include <config.h>
22 #include <alloca.h>
24 #include <sys/types.h>
26 /* Specification. */
27 #include <poll.h>
29 #include <errno.h>
30 #include <limits.h>
32 #if defined _WIN32 && ! defined __CYGWIN__
33 # define WINDOWS_NATIVE
34 # include <winsock2.h>
35 # include <windows.h>
36 # include <io.h>
37 # include <stdio.h>
38 # include <conio.h>
39 # if GNULIB_MSVC_NOTHROW
40 # include "msvc-nothrow.h"
41 # else
42 # include <io.h>
43 # endif
44 #else
45 # include <sys/time.h>
46 # include <unistd.h>
47 #endif
49 #include <sys/select.h>
50 #include <sys/socket.h>
52 #ifdef HAVE_SYS_IOCTL_H
53 # include <sys/ioctl.h>
54 #endif
55 #ifdef HAVE_SYS_FILIO_H
56 # include <sys/filio.h>
57 #endif
59 #include <time.h>
61 #include "assure.h"
63 #ifndef INFTIM
64 # define INFTIM (-1)
65 #endif
67 /* BeOS does not have MSG_PEEK. */
68 #ifndef MSG_PEEK
69 # define MSG_PEEK 0
70 #endif
72 #ifdef WINDOWS_NATIVE
74 /* Don't assume that UNICODE is not defined. */
75 # undef GetModuleHandle
76 # define GetModuleHandle GetModuleHandleA
77 # undef PeekConsoleInput
78 # define PeekConsoleInput PeekConsoleInputA
79 # undef CreateEvent
80 # define CreateEvent CreateEventA
81 # undef PeekMessage
82 # define PeekMessage PeekMessageA
83 # undef DispatchMessage
84 # define DispatchMessage DispatchMessageA
86 /* Do *not* use the function WSAPoll
87 <https://docs.microsoft.com/en-us/windows/desktop/api/winsock2/nf-winsock2-wsapoll>
88 because there is a bug named “Windows 8 Bugs 309411 - WSAPoll does not
89 report failed connections” that Microsoft won't fix.
90 See Daniel Stenberg: "WASPoll is broken"
91 <https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/>. */
93 /* Here we need the recv() function from Windows, that takes a SOCKET as
94 first argument, not any possible gnulib override. */
95 # undef recv
97 /* Here we need the select() function from Windows, because we pass bit masks
98 of SOCKETs, not bit masks of FDs. */
99 # undef select
101 /* Here we need timeval from Windows since this is what the select() function
102 from Windows requires. */
103 # undef timeval
105 /* Avoid warnings from gcc -Wcast-function-type. */
106 # define GetProcAddress \
107 (void *) GetProcAddress
109 static BOOL IsConsoleHandle (HANDLE h)
111 DWORD mode;
112 return GetConsoleMode (h, &mode) != 0;
115 static BOOL
116 IsSocketHandle (HANDLE h)
118 WSANETWORKEVENTS ev;
120 if (IsConsoleHandle (h))
121 return FALSE;
123 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
124 WSAEnumNetworkEvents instead distinguishes the two correctly. */
125 ev.lNetworkEvents = 0xDEADBEEF;
126 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
127 return ev.lNetworkEvents != 0xDEADBEEF;
130 /* Declare data structures for ntdll functions. */
131 typedef struct _FILE_PIPE_LOCAL_INFORMATION {
132 ULONG NamedPipeType;
133 ULONG NamedPipeConfiguration;
134 ULONG MaximumInstances;
135 ULONG CurrentInstances;
136 ULONG InboundQuota;
137 ULONG ReadDataAvailable;
138 ULONG OutboundQuota;
139 ULONG WriteQuotaAvailable;
140 ULONG NamedPipeState;
141 ULONG NamedPipeEnd;
142 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
144 typedef struct _IO_STATUS_BLOCK
146 union {
147 DWORD Status;
148 PVOID Pointer;
149 } u;
150 ULONG_PTR Information;
151 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
153 typedef enum _FILE_INFORMATION_CLASS {
154 FilePipeLocalInformation = 24
155 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
157 typedef DWORD (WINAPI *PNtQueryInformationFile)
158 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
160 # ifndef PIPE_BUF
161 # define PIPE_BUF 512
162 # endif
164 /* Compute revents values for file handle H. If some events cannot happen
165 for the handle, eliminate them from *P_SOUGHT. */
167 static int
168 windows_compute_revents (HANDLE h, int *p_sought)
170 int i, ret, happened;
171 INPUT_RECORD *irbuffer;
172 DWORD avail, nbuffer;
173 BOOL bRet;
174 IO_STATUS_BLOCK iosb;
175 FILE_PIPE_LOCAL_INFORMATION fpli;
176 static PNtQueryInformationFile NtQueryInformationFile;
177 static BOOL once_only;
179 switch (GetFileType (h))
181 case FILE_TYPE_PIPE:
182 if (!once_only)
184 NtQueryInformationFile = (PNtQueryInformationFile)
185 GetProcAddress (GetModuleHandle ("ntdll.dll"),
186 "NtQueryInformationFile");
187 once_only = TRUE;
190 happened = 0;
191 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
193 if (avail)
194 happened |= *p_sought & (POLLIN | POLLRDNORM);
196 else if (GetLastError () == ERROR_BROKEN_PIPE)
197 happened |= POLLHUP;
199 else
201 /* It was the write-end of the pipe. Check if it is writable.
202 If NtQueryInformationFile fails, optimistically assume the pipe is
203 writable. This could happen on Windows 9x, where
204 NtQueryInformationFile is not available, or if we inherit a pipe
205 that doesn't permit FILE_READ_ATTRIBUTES access on the write end
206 (I think this should not happen since Windows XP SP2; WINE seems
207 fine too). Otherwise, ensure that enough space is available for
208 atomic writes. */
209 memset (&iosb, 0, sizeof (iosb));
210 memset (&fpli, 0, sizeof (fpli));
212 if (!NtQueryInformationFile
213 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
214 FilePipeLocalInformation)
215 || fpli.WriteQuotaAvailable >= PIPE_BUF
216 || (fpli.OutboundQuota < PIPE_BUF &&
217 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
218 happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
220 return happened;
222 case FILE_TYPE_CHAR:
223 ret = WaitForSingleObject (h, 0);
224 if (!IsConsoleHandle (h))
225 return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
227 nbuffer = avail = 0;
228 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
229 if (bRet)
231 /* Input buffer. */
232 *p_sought &= POLLIN | POLLRDNORM;
233 if (nbuffer == 0)
234 return POLLHUP;
235 if (!*p_sought)
236 return 0;
238 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
239 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
240 if (!bRet || avail == 0)
241 return POLLHUP;
243 for (i = 0; i < avail; i++)
244 if (irbuffer[i].EventType == KEY_EVENT)
245 return *p_sought;
246 return 0;
248 else
250 /* Screen buffer. */
251 *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
252 return *p_sought;
255 default:
256 ret = WaitForSingleObject (h, 0);
257 if (ret == WAIT_OBJECT_0)
258 return *p_sought & ~(POLLPRI | POLLRDBAND);
260 return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
264 /* Convert fd_sets returned by select into revents values. */
266 static int
267 windows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
269 int happened = 0;
271 if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
272 happened |= (POLLIN | POLLRDNORM) & sought;
274 else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
276 int r, error;
278 char data[64];
279 WSASetLastError (0);
280 r = recv (h, data, sizeof (data), MSG_PEEK);
281 error = WSAGetLastError ();
282 WSASetLastError (0);
284 if (r > 0 || error == WSAENOTCONN)
285 happened |= (POLLIN | POLLRDNORM) & sought;
287 /* Distinguish hung-up sockets from other errors. */
288 else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
289 || error == WSAECONNABORTED || error == WSAENETRESET)
290 happened |= POLLHUP;
292 else
293 happened |= POLLERR;
296 if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
297 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
299 if (lNetworkEvents & FD_OOB)
300 happened |= (POLLPRI | POLLRDBAND) & sought;
302 return happened;
305 #else /* !MinGW */
307 /* Convert select(2) returned fd_sets into poll(2) revents values. */
308 static int
309 compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
311 int happened = 0;
312 if (FD_ISSET (fd, rfds))
314 int r;
315 int socket_errno;
317 # if defined __MACH__ && defined __APPLE__
318 /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
319 for some kinds of descriptors. Detect if this descriptor is a
320 connected socket, a server socket, or something else using a
321 0-byte recv, and use ioctl(2) to detect POLLHUP. */
322 r = recv (fd, NULL, 0, MSG_PEEK);
323 socket_errno = (r < 0) ? errno : 0;
324 if (r == 0 || socket_errno == ENOTSOCK)
325 ioctl (fd, FIONREAD, &r);
326 # else
327 char data[64];
328 r = recv (fd, data, sizeof (data), MSG_PEEK);
329 socket_errno = (r < 0) ? errno : 0;
330 # endif
331 if (r == 0)
332 happened |= POLLHUP;
334 /* If the event happened on an unconnected server socket,
335 that's fine. */
336 else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
337 happened |= (POLLIN | POLLRDNORM) & sought;
339 /* Distinguish hung-up sockets from other errors. */
340 else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
341 || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
342 happened |= POLLHUP;
344 /* some systems can't use recv() on non-socket, including HP NonStop */
345 else if (socket_errno == ENOTSOCK)
346 happened |= (POLLIN | POLLRDNORM) & sought;
348 else
349 happened |= POLLERR;
352 if (FD_ISSET (fd, wfds))
353 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
355 if (FD_ISSET (fd, efds))
356 happened |= (POLLPRI | POLLRDBAND) & sought;
358 return happened;
360 #endif /* !MinGW */
363 poll (struct pollfd *pfd, nfds_t nfd, int timeout)
365 #ifndef WINDOWS_NATIVE
366 fd_set rfds, wfds, efds;
367 struct timeval tv;
368 struct timeval *ptv;
369 int maxfd, rc;
370 nfds_t i;
372 if (nfd > INT_MAX)
374 errno = EINVAL;
375 return -1;
377 /* Don't check directly for NFD greater than OPEN_MAX. Any practical use
378 of a too-large NFD is caught by one of the other checks below, and
379 checking directly for getdtablesize is too much of a portability
380 and/or performance and/or correctness hassle. */
382 /* EFAULT is not necessary to implement, but let's do it in the
383 simplest case. */
384 if (!pfd && nfd)
386 errno = EFAULT;
387 return -1;
390 /* convert timeout number into a timeval structure */
391 if (timeout == 0)
393 ptv = &tv;
394 tv = (struct timeval) {0};
396 else if (timeout > 0)
398 ptv = &tv;
399 tv = (struct timeval) {
400 .tv_sec = timeout / 1000,
401 .tv_usec = (timeout % 1000) * 1000
404 else if (timeout == INFTIM)
405 /* wait forever */
406 ptv = NULL;
407 else
409 errno = EINVAL;
410 return -1;
413 /* create fd sets and determine max fd */
414 maxfd = -1;
415 FD_ZERO (&rfds);
416 FD_ZERO (&wfds);
417 FD_ZERO (&efds);
418 for (i = 0; i < nfd; i++)
420 if (pfd[i].fd < 0)
421 continue;
422 if (maxfd < pfd[i].fd)
424 maxfd = pfd[i].fd;
425 if (FD_SETSIZE <= maxfd)
427 errno = EINVAL;
428 return -1;
431 if (pfd[i].events & (POLLIN | POLLRDNORM))
432 FD_SET (pfd[i].fd, &rfds);
433 /* see select(2): "the only exceptional condition detectable
434 is out-of-band data received on a socket", hence we push
435 POLLWRBAND events onto wfds instead of efds. */
436 if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
437 FD_SET (pfd[i].fd, &wfds);
438 if (pfd[i].events & (POLLPRI | POLLRDBAND))
439 FD_SET (pfd[i].fd, &efds);
442 /* examine fd sets */
443 rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
444 if (rc < 0)
445 return rc;
447 /* establish results */
448 rc = 0;
449 for (i = 0; i < nfd; i++)
451 pfd[i].revents = (pfd[i].fd < 0
453 : compute_revents (pfd[i].fd, pfd[i].events,
454 &rfds, &wfds, &efds));
455 rc += pfd[i].revents != 0;
458 return rc;
459 #else
460 static struct timeval tv0;
461 static HANDLE hEvent;
462 WSANETWORKEVENTS ev;
463 HANDLE h, handle_array[FD_SETSIZE + 2];
464 DWORD ret, wait_timeout, nhandles;
465 fd_set rfds, wfds, xfds;
466 BOOL poll_again;
467 MSG msg;
468 int rc = 0;
469 nfds_t i;
471 if (nfd > INT_MAX || timeout < -1)
473 errno = EINVAL;
474 return -1;
477 if (!hEvent)
478 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
480 restart:
481 handle_array[0] = hEvent;
482 nhandles = 1;
483 FD_ZERO (&rfds);
484 FD_ZERO (&wfds);
485 FD_ZERO (&xfds);
487 /* Classify socket handles and create fd sets. */
488 for (i = 0; i < nfd; i++)
490 int sought = pfd[i].events;
491 pfd[i].revents = 0;
492 if (pfd[i].fd < 0)
493 continue;
494 if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
495 | POLLPRI | POLLRDBAND)))
496 continue;
498 h = (HANDLE) _get_osfhandle (pfd[i].fd);
499 assure (h != NULL);
500 if (IsSocketHandle (h))
502 int requested = FD_CLOSE;
504 /* see above; socket handles are mapped onto select. */
505 if (sought & (POLLIN | POLLRDNORM))
507 requested |= FD_READ | FD_ACCEPT;
508 FD_SET ((SOCKET) h, &rfds);
510 if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
512 requested |= FD_WRITE | FD_CONNECT;
513 FD_SET ((SOCKET) h, &wfds);
515 if (sought & (POLLPRI | POLLRDBAND))
517 requested |= FD_OOB;
518 FD_SET ((SOCKET) h, &xfds);
521 if (requested)
522 WSAEventSelect ((SOCKET) h, hEvent, requested);
524 else
526 /* Poll now. If we get an event, do not poll again. Also,
527 screen buffer handles are waitable, and they'll block until
528 a character is available. windows_compute_revents eliminates
529 bits for the "wrong" direction. */
530 pfd[i].revents = windows_compute_revents (h, &sought);
531 if (sought)
532 handle_array[nhandles++] = h;
533 if (pfd[i].revents)
534 timeout = 0;
538 if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
540 /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
541 no need to call select again. */
542 poll_again = FALSE;
543 wait_timeout = 0;
545 else
547 poll_again = TRUE;
548 if (timeout == INFTIM)
549 wait_timeout = INFINITE;
550 else
551 wait_timeout = timeout;
554 for (;;)
556 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
557 wait_timeout, QS_ALLINPUT);
559 if (ret == WAIT_OBJECT_0 + nhandles)
561 /* new input of some other kind */
562 BOOL bRet;
563 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
565 TranslateMessage (&msg);
566 DispatchMessage (&msg);
569 else
570 break;
573 if (poll_again)
574 select (0, &rfds, &wfds, &xfds, &tv0);
576 /* Place a sentinel at the end of the array. */
577 handle_array[nhandles] = NULL;
578 nhandles = 1;
579 for (i = 0; i < nfd; i++)
581 int happened;
583 if (pfd[i].fd < 0)
584 continue;
585 if (!(pfd[i].events & (POLLIN | POLLRDNORM |
586 POLLOUT | POLLWRNORM | POLLWRBAND)))
587 continue;
589 h = (HANDLE) _get_osfhandle (pfd[i].fd);
590 if (h != handle_array[nhandles])
592 /* It's a socket. */
593 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
594 WSAEventSelect ((SOCKET) h, 0, 0);
596 /* If we're lucky, WSAEnumNetworkEvents already provided a way
597 to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
598 if (FD_ISSET ((SOCKET) h, &rfds)
599 && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
600 ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
601 if (FD_ISSET ((SOCKET) h, &wfds))
602 ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
603 if (FD_ISSET ((SOCKET) h, &xfds))
604 ev.lNetworkEvents |= FD_OOB;
606 happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events,
607 ev.lNetworkEvents);
609 else
611 /* Not a socket. */
612 int sought = pfd[i].events;
613 happened = windows_compute_revents (h, &sought);
614 nhandles++;
617 if ((pfd[i].revents |= happened) != 0)
618 rc++;
621 if (!rc && timeout == INFTIM)
623 SleepEx (1, TRUE);
624 goto restart;
627 return rc;
628 #endif