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