Git fork
at reftables-rust 610 lines 15 kB view raw
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 Vista */ 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 0x0502 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 85static BOOL 86IsSocketHandle (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. */ 101typedef 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 114typedef 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 123typedef enum _FILE_INFORMATION_CLASS { 124 FilePipeLocalInformation = 24 125} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; 126 127typedef 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 137static int 138win32_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 210static int 211win32_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. */ 252static int 253compute_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 306int 307poll (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 455restart: 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}