This source file includes following definitions.
- IsConsoleHandle
- IsSocketHandle
- windows_compute_revents
- windows_compute_revents_socket
- compute_revents
- poll
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
32 #include <poll.h>
33
34 #include <errno.h>
35 #include <limits.h>
36
37 #if 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 # if GNULIB_MSVC_NOTHROW
45 # include "msvc-nothrow.h"
46 # else
47 # include <io.h>
48 # endif
49 #else
50 # include <sys/time.h>
51 # include <unistd.h>
52 #endif
53
54 #include <sys/select.h>
55 #include <sys/socket.h>
56
57 #ifdef HAVE_SYS_IOCTL_H
58 # include <sys/ioctl.h>
59 #endif
60 #ifdef HAVE_SYS_FILIO_H
61 # include <sys/filio.h>
62 #endif
63
64 #include <time.h>
65
66 #include "assure.h"
67
68 #ifndef INFTIM
69 # define INFTIM (-1)
70 #endif
71
72
73 #ifndef MSG_PEEK
74 # define MSG_PEEK 0
75 #endif
76
77 #ifdef WINDOWS_NATIVE
78
79
80 # undef GetModuleHandle
81 # define GetModuleHandle GetModuleHandleA
82 # undef PeekConsoleInput
83 # define PeekConsoleInput PeekConsoleInputA
84 # undef CreateEvent
85 # define CreateEvent CreateEventA
86 # undef PeekMessage
87 # define PeekMessage PeekMessageA
88 # undef DispatchMessage
89 # define DispatchMessage DispatchMessageA
90
91
92
93
94
95
96
97
98
99
100 # undef recv
101
102
103
104 # undef select
105
106
107
108 # undef timeval
109
110
111 # define GetProcAddress \
112 (void *) GetProcAddress
113
114 static BOOL IsConsoleHandle (HANDLE h)
115 {
116 DWORD mode;
117 return GetConsoleMode (h, &mode) != 0;
118 }
119
120 static BOOL
121 IsSocketHandle (HANDLE h)
122 {
123 WSANETWORKEVENTS ev;
124
125 if (IsConsoleHandle (h))
126 return FALSE;
127
128
129
130 ev.lNetworkEvents = 0xDEADBEEF;
131 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
132 return ev.lNetworkEvents != 0xDEADBEEF;
133 }
134
135
136 typedef struct _FILE_PIPE_LOCAL_INFORMATION {
137 ULONG NamedPipeType;
138 ULONG NamedPipeConfiguration;
139 ULONG MaximumInstances;
140 ULONG CurrentInstances;
141 ULONG InboundQuota;
142 ULONG ReadDataAvailable;
143 ULONG OutboundQuota;
144 ULONG WriteQuotaAvailable;
145 ULONG NamedPipeState;
146 ULONG NamedPipeEnd;
147 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
148
149 typedef struct _IO_STATUS_BLOCK
150 {
151 union {
152 DWORD Status;
153 PVOID Pointer;
154 } u;
155 ULONG_PTR Information;
156 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
157
158 typedef enum _FILE_INFORMATION_CLASS {
159 FilePipeLocalInformation = 24
160 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
161
162 typedef DWORD (WINAPI *PNtQueryInformationFile)
163 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
164
165 # ifndef PIPE_BUF
166 # define PIPE_BUF 512
167 # endif
168
169
170
171
172 static int
173 windows_compute_revents (HANDLE h, int *p_sought)
174 {
175 int i, ret, happened;
176 INPUT_RECORD *irbuffer;
177 DWORD avail, nbuffer;
178 BOOL bRet;
179 IO_STATUS_BLOCK iosb;
180 FILE_PIPE_LOCAL_INFORMATION fpli;
181 static PNtQueryInformationFile NtQueryInformationFile;
182 static BOOL once_only;
183
184 switch (GetFileType (h))
185 {
186 case FILE_TYPE_PIPE:
187 if (!once_only)
188 {
189 NtQueryInformationFile = (PNtQueryInformationFile)
190 GetProcAddress (GetModuleHandle ("ntdll.dll"),
191 "NtQueryInformationFile");
192 once_only = TRUE;
193 }
194
195 happened = 0;
196 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
197 {
198 if (avail)
199 happened |= *p_sought & (POLLIN | POLLRDNORM);
200 }
201 else if (GetLastError () == ERROR_BROKEN_PIPE)
202 happened |= POLLHUP;
203
204 else
205 {
206
207
208
209
210
211
212
213
214 memset (&iosb, 0, sizeof (iosb));
215 memset (&fpli, 0, sizeof (fpli));
216
217 if (!NtQueryInformationFile
218 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
219 FilePipeLocalInformation)
220 || fpli.WriteQuotaAvailable >= PIPE_BUF
221 || (fpli.OutboundQuota < PIPE_BUF &&
222 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
223 happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
224 }
225 return happened;
226
227 case FILE_TYPE_CHAR:
228 ret = WaitForSingleObject (h, 0);
229 if (!IsConsoleHandle (h))
230 return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
231
232 nbuffer = avail = 0;
233 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
234 if (bRet)
235 {
236
237 *p_sought &= POLLIN | POLLRDNORM;
238 if (nbuffer == 0)
239 return POLLHUP;
240 if (!*p_sought)
241 return 0;
242
243 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
244 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
245 if (!bRet || avail == 0)
246 return POLLHUP;
247
248 for (i = 0; i < avail; i++)
249 if (irbuffer[i].EventType == KEY_EVENT)
250 return *p_sought;
251 return 0;
252 }
253 else
254 {
255
256 *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
257 return *p_sought;
258 }
259
260 default:
261 ret = WaitForSingleObject (h, 0);
262 if (ret == WAIT_OBJECT_0)
263 return *p_sought & ~(POLLPRI | POLLRDBAND);
264
265 return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
266 }
267 }
268
269
270
271 static int
272 windows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
273 {
274 int happened = 0;
275
276 if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
277 happened |= (POLLIN | POLLRDNORM) & sought;
278
279 else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
280 {
281 int r, error;
282
283 char data[64];
284 WSASetLastError (0);
285 r = recv (h, data, sizeof (data), MSG_PEEK);
286 error = WSAGetLastError ();
287 WSASetLastError (0);
288
289 if (r > 0 || error == WSAENOTCONN)
290 happened |= (POLLIN | POLLRDNORM) & sought;
291
292
293 else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
294 || error == WSAECONNABORTED || error == WSAENETRESET)
295 happened |= POLLHUP;
296
297 else
298 happened |= POLLERR;
299 }
300
301 if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
302 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
303
304 if (lNetworkEvents & FD_OOB)
305 happened |= (POLLPRI | POLLRDBAND) & sought;
306
307 return happened;
308 }
309
310 #else
311
312
313 static int
314 compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
315 {
316 int happened = 0;
317 if (FD_ISSET (fd, rfds))
318 {
319 int r;
320 int socket_errno;
321
322 # if defined __MACH__ && defined __APPLE__
323
324
325
326
327 r = recv (fd, NULL, 0, MSG_PEEK);
328 socket_errno = (r < 0) ? errno : 0;
329 if (r == 0 || socket_errno == ENOTSOCK)
330 ioctl (fd, FIONREAD, &r);
331 # else
332 char data[64];
333 r = recv (fd, data, sizeof (data), MSG_PEEK);
334 socket_errno = (r < 0) ? errno : 0;
335 # endif
336 if (r == 0)
337 happened |= POLLHUP;
338
339
340
341 else if (r > 0 || ( socket_errno == ENOTCONN))
342 happened |= (POLLIN | POLLRDNORM) & sought;
343
344
345 else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
346 || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
347 happened |= POLLHUP;
348
349
350 else if (socket_errno == ENOTSOCK)
351 happened |= (POLLIN | POLLRDNORM) & sought;
352
353 else
354 happened |= POLLERR;
355 }
356
357 if (FD_ISSET (fd, wfds))
358 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
359
360 if (FD_ISSET (fd, efds))
361 happened |= (POLLPRI | POLLRDBAND) & sought;
362
363 return happened;
364 }
365 #endif
366
367 int
368 poll (struct pollfd *pfd, nfds_t nfd, int timeout)
369 {
370 #ifndef WINDOWS_NATIVE
371 fd_set rfds, wfds, efds;
372 struct timeval tv;
373 struct timeval *ptv;
374 int maxfd, rc;
375 nfds_t i;
376
377 if (nfd > INT_MAX)
378 {
379 errno = EINVAL;
380 return -1;
381 }
382
383
384
385
386
387
388
389 if (!pfd && nfd)
390 {
391 errno = EFAULT;
392 return -1;
393 }
394
395
396 if (timeout == 0)
397 {
398 ptv = &tv;
399 ptv->tv_sec = 0;
400 ptv->tv_usec = 0;
401 }
402 else if (timeout > 0)
403 {
404 ptv = &tv;
405 ptv->tv_sec = timeout / 1000;
406 ptv->tv_usec = (timeout % 1000) * 1000;
407 }
408 else if (timeout == INFTIM)
409
410 ptv = NULL;
411 else
412 {
413 errno = EINVAL;
414 return -1;
415 }
416
417
418 maxfd = -1;
419 FD_ZERO (&rfds);
420 FD_ZERO (&wfds);
421 FD_ZERO (&efds);
422 for (i = 0; i < nfd; i++)
423 {
424 if (pfd[i].fd < 0)
425 continue;
426 if (maxfd < pfd[i].fd)
427 {
428 maxfd = pfd[i].fd;
429 if (FD_SETSIZE <= maxfd)
430 {
431 errno = EINVAL;
432 return -1;
433 }
434 }
435 if (pfd[i].events & (POLLIN | POLLRDNORM))
436 FD_SET (pfd[i].fd, &rfds);
437
438
439
440 if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
441 FD_SET (pfd[i].fd, &wfds);
442 if (pfd[i].events & (POLLPRI | POLLRDBAND))
443 FD_SET (pfd[i].fd, &efds);
444 }
445
446
447 rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
448 if (rc < 0)
449 return rc;
450
451
452 rc = 0;
453 for (i = 0; i < nfd; i++)
454 {
455 pfd[i].revents = (pfd[i].fd < 0
456 ? 0
457 : compute_revents (pfd[i].fd, pfd[i].events,
458 &rfds, &wfds, &efds));
459 rc += pfd[i].revents != 0;
460 }
461
462 return rc;
463 #else
464 static struct timeval tv0;
465 static HANDLE hEvent;
466 WSANETWORKEVENTS ev;
467 HANDLE h, handle_array[FD_SETSIZE + 2];
468 DWORD ret, wait_timeout, nhandles;
469 fd_set rfds, wfds, xfds;
470 BOOL poll_again;
471 MSG msg;
472 int rc = 0;
473 nfds_t i;
474
475 if (nfd > INT_MAX || timeout < -1)
476 {
477 errno = EINVAL;
478 return -1;
479 }
480
481 if (!hEvent)
482 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
483
484 restart:
485 handle_array[0] = hEvent;
486 nhandles = 1;
487 FD_ZERO (&rfds);
488 FD_ZERO (&wfds);
489 FD_ZERO (&xfds);
490
491
492 for (i = 0; i < nfd; i++)
493 {
494 int sought = pfd[i].events;
495 pfd[i].revents = 0;
496 if (pfd[i].fd < 0)
497 continue;
498 if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
499 | POLLPRI | POLLRDBAND)))
500 continue;
501
502 h = (HANDLE) _get_osfhandle (pfd[i].fd);
503 assure (h != NULL);
504 if (IsSocketHandle (h))
505 {
506 int requested = FD_CLOSE;
507
508
509 if (sought & (POLLIN | POLLRDNORM))
510 {
511 requested |= FD_READ | FD_ACCEPT;
512 FD_SET ((SOCKET) h, &rfds);
513 }
514 if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
515 {
516 requested |= FD_WRITE | FD_CONNECT;
517 FD_SET ((SOCKET) h, &wfds);
518 }
519 if (sought & (POLLPRI | POLLRDBAND))
520 {
521 requested |= FD_OOB;
522 FD_SET ((SOCKET) h, &xfds);
523 }
524
525 if (requested)
526 WSAEventSelect ((SOCKET) h, hEvent, requested);
527 }
528 else
529 {
530
531
532
533
534 pfd[i].revents = windows_compute_revents (h, &sought);
535 if (sought)
536 handle_array[nhandles++] = h;
537 if (pfd[i].revents)
538 timeout = 0;
539 }
540 }
541
542 if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
543 {
544
545
546 poll_again = FALSE;
547 wait_timeout = 0;
548 }
549 else
550 {
551 poll_again = TRUE;
552 if (timeout == INFTIM)
553 wait_timeout = INFINITE;
554 else
555 wait_timeout = timeout;
556 }
557
558 for (;;)
559 {
560 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
561 wait_timeout, QS_ALLINPUT);
562
563 if (ret == WAIT_OBJECT_0 + nhandles)
564 {
565
566 BOOL bRet;
567 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
568 {
569 TranslateMessage (&msg);
570 DispatchMessage (&msg);
571 }
572 }
573 else
574 break;
575 }
576
577 if (poll_again)
578 select (0, &rfds, &wfds, &xfds, &tv0);
579
580
581 handle_array[nhandles] = NULL;
582 nhandles = 1;
583 for (i = 0; i < nfd; i++)
584 {
585 int happened;
586
587 if (pfd[i].fd < 0)
588 continue;
589 if (!(pfd[i].events & (POLLIN | POLLRDNORM |
590 POLLOUT | POLLWRNORM | POLLWRBAND)))
591 continue;
592
593 h = (HANDLE) _get_osfhandle (pfd[i].fd);
594 if (h != handle_array[nhandles])
595 {
596
597 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
598 WSAEventSelect ((SOCKET) h, 0, 0);
599
600
601
602 if (FD_ISSET ((SOCKET) h, &rfds)
603 && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
604 ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
605 if (FD_ISSET ((SOCKET) h, &wfds))
606 ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
607 if (FD_ISSET ((SOCKET) h, &xfds))
608 ev.lNetworkEvents |= FD_OOB;
609
610 happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events,
611 ev.lNetworkEvents);
612 }
613 else
614 {
615
616 int sought = pfd[i].events;
617 happened = windows_compute_revents (h, &sought);
618 nhandles++;
619 }
620
621 if ((pfd[i].revents |= happened) != 0)
622 rc++;
623 }
624
625 if (!rc && timeout == INFTIM)
626 {
627 SleepEx (1, TRUE);
628 goto restart;
629 }
630
631 return rc;
632 #endif
633 }