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