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