PageRenderTime 24ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/poll.c

https://gitlab.com/wilfred/guile
C | 594 lines | 436 code | 82 blank | 76 comment | 139 complexity | af18d74e9ce810fdbf31c86a76045d56 MD5 | raw file
  1. /* Emulation for poll(2)
  2. Contributed by Paolo Bonzini.
  3. Copyright 2001-2003, 2006-2016 Free Software Foundation, Inc.
  4. This file is part of gnulib.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License along
  14. with this program; if not, see <http://www.gnu.org/licenses/>. */
  15. /* Tell gcc not to warn about the (nfd < 0) tests, below. */
  16. #if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
  17. # pragma GCC diagnostic ignored "-Wtype-limits"
  18. #endif
  19. #include <config.h>
  20. #include <alloca.h>
  21. #include <sys/types.h>
  22. /* Specification. */
  23. #include <poll.h>
  24. #include <errno.h>
  25. #include <limits.h>
  26. #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
  27. # define WINDOWS_NATIVE
  28. # include <winsock2.h>
  29. # include <windows.h>
  30. # include <io.h>
  31. # include <stdio.h>
  32. # include <conio.h>
  33. # include "msvc-nothrow.h"
  34. #else
  35. # include <sys/time.h>
  36. # include <unistd.h>
  37. #endif
  38. #include <sys/select.h>
  39. #include <sys/socket.h>
  40. #ifdef HAVE_SYS_IOCTL_H
  41. # include <sys/ioctl.h>
  42. #endif
  43. #ifdef HAVE_SYS_FILIO_H
  44. # include <sys/filio.h>
  45. #endif
  46. #include <time.h>
  47. #include "assure.h"
  48. #ifndef INFTIM
  49. # define INFTIM (-1)
  50. #endif
  51. /* BeOS does not have MSG_PEEK. */
  52. #ifndef MSG_PEEK
  53. # define MSG_PEEK 0
  54. #endif
  55. #ifdef WINDOWS_NATIVE
  56. static BOOL IsConsoleHandle (HANDLE h)
  57. {
  58. DWORD mode;
  59. return GetConsoleMode (h, &mode) != 0;
  60. }
  61. static BOOL
  62. IsSocketHandle (HANDLE h)
  63. {
  64. WSANETWORKEVENTS ev;
  65. if (IsConsoleHandle (h))
  66. return FALSE;
  67. /* Under Wine, it seems that getsockopt returns 0 for pipes too.
  68. WSAEnumNetworkEvents instead distinguishes the two correctly. */
  69. ev.lNetworkEvents = 0xDEADBEEF;
  70. WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
  71. return ev.lNetworkEvents != 0xDEADBEEF;
  72. }
  73. /* Declare data structures for ntdll functions. */
  74. typedef struct _FILE_PIPE_LOCAL_INFORMATION {
  75. ULONG NamedPipeType;
  76. ULONG NamedPipeConfiguration;
  77. ULONG MaximumInstances;
  78. ULONG CurrentInstances;
  79. ULONG InboundQuota;
  80. ULONG ReadDataAvailable;
  81. ULONG OutboundQuota;
  82. ULONG WriteQuotaAvailable;
  83. ULONG NamedPipeState;
  84. ULONG NamedPipeEnd;
  85. } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
  86. typedef struct _IO_STATUS_BLOCK
  87. {
  88. union {
  89. DWORD Status;
  90. PVOID Pointer;
  91. } u;
  92. ULONG_PTR Information;
  93. } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
  94. typedef enum _FILE_INFORMATION_CLASS {
  95. FilePipeLocalInformation = 24
  96. } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
  97. typedef DWORD (WINAPI *PNtQueryInformationFile)
  98. (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
  99. # ifndef PIPE_BUF
  100. # define PIPE_BUF 512
  101. # endif
  102. /* Compute revents values for file handle H. If some events cannot happen
  103. for the handle, eliminate them from *P_SOUGHT. */
  104. static int
  105. windows_compute_revents (HANDLE h, int *p_sought)
  106. {
  107. int i, ret, happened;
  108. INPUT_RECORD *irbuffer;
  109. DWORD avail, nbuffer;
  110. BOOL bRet;
  111. IO_STATUS_BLOCK iosb;
  112. FILE_PIPE_LOCAL_INFORMATION fpli;
  113. static PNtQueryInformationFile NtQueryInformationFile;
  114. static BOOL once_only;
  115. switch (GetFileType (h))
  116. {
  117. case FILE_TYPE_PIPE:
  118. if (!once_only)
  119. {
  120. NtQueryInformationFile = (PNtQueryInformationFile)
  121. GetProcAddress (GetModuleHandle ("ntdll.dll"),
  122. "NtQueryInformationFile");
  123. once_only = TRUE;
  124. }
  125. happened = 0;
  126. if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
  127. {
  128. if (avail)
  129. happened |= *p_sought & (POLLIN | POLLRDNORM);
  130. }
  131. else if (GetLastError () == ERROR_BROKEN_PIPE)
  132. happened |= POLLHUP;
  133. else
  134. {
  135. /* It was the write-end of the pipe. Check if it is writable.
  136. If NtQueryInformationFile fails, optimistically assume the pipe is
  137. writable. This could happen on Windows 9x, where
  138. NtQueryInformationFile is not available, or if we inherit a pipe
  139. that doesn't permit FILE_READ_ATTRIBUTES access on the write end
  140. (I think this should not happen since Windows XP SP2; WINE seems
  141. fine too). Otherwise, ensure that enough space is available for
  142. atomic writes. */
  143. memset (&iosb, 0, sizeof (iosb));
  144. memset (&fpli, 0, sizeof (fpli));
  145. if (!NtQueryInformationFile
  146. || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
  147. FilePipeLocalInformation)
  148. || fpli.WriteQuotaAvailable >= PIPE_BUF
  149. || (fpli.OutboundQuota < PIPE_BUF &&
  150. fpli.WriteQuotaAvailable == fpli.OutboundQuota))
  151. happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
  152. }
  153. return happened;
  154. case FILE_TYPE_CHAR:
  155. ret = WaitForSingleObject (h, 0);
  156. if (!IsConsoleHandle (h))
  157. return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
  158. nbuffer = avail = 0;
  159. bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
  160. if (bRet)
  161. {
  162. /* Input buffer. */
  163. *p_sought &= POLLIN | POLLRDNORM;
  164. if (nbuffer == 0)
  165. return POLLHUP;
  166. if (!*p_sought)
  167. return 0;
  168. irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
  169. bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
  170. if (!bRet || avail == 0)
  171. return POLLHUP;
  172. for (i = 0; i < avail; i++)
  173. if (irbuffer[i].EventType == KEY_EVENT)
  174. return *p_sought;
  175. return 0;
  176. }
  177. else
  178. {
  179. /* Screen buffer. */
  180. *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
  181. return *p_sought;
  182. }
  183. default:
  184. ret = WaitForSingleObject (h, 0);
  185. if (ret == WAIT_OBJECT_0)
  186. return *p_sought & ~(POLLPRI | POLLRDBAND);
  187. return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
  188. }
  189. }
  190. /* Convert fd_sets returned by select into revents values. */
  191. static int
  192. windows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
  193. {
  194. int happened = 0;
  195. if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
  196. happened |= (POLLIN | POLLRDNORM) & sought;
  197. else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
  198. {
  199. int r, error;
  200. char data[64];
  201. WSASetLastError (0);
  202. r = recv (h, data, sizeof (data), MSG_PEEK);
  203. error = WSAGetLastError ();
  204. WSASetLastError (0);
  205. if (r > 0 || error == WSAENOTCONN)
  206. happened |= (POLLIN | POLLRDNORM) & sought;
  207. /* Distinguish hung-up sockets from other errors. */
  208. else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
  209. || error == WSAECONNABORTED || error == WSAENETRESET)
  210. happened |= POLLHUP;
  211. else
  212. happened |= POLLERR;
  213. }
  214. if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
  215. happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
  216. if (lNetworkEvents & FD_OOB)
  217. happened |= (POLLPRI | POLLRDBAND) & sought;
  218. return happened;
  219. }
  220. #else /* !MinGW */
  221. /* Convert select(2) returned fd_sets into poll(2) revents values. */
  222. static int
  223. compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
  224. {
  225. int happened = 0;
  226. if (FD_ISSET (fd, rfds))
  227. {
  228. int r;
  229. int socket_errno;
  230. # if defined __MACH__ && defined __APPLE__
  231. /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
  232. for some kinds of descriptors. Detect if this descriptor is a
  233. connected socket, a server socket, or something else using a
  234. 0-byte recv, and use ioctl(2) to detect POLLHUP. */
  235. r = recv (fd, NULL, 0, MSG_PEEK);
  236. socket_errno = (r < 0) ? errno : 0;
  237. if (r == 0 || socket_errno == ENOTSOCK)
  238. ioctl (fd, FIONREAD, &r);
  239. # else
  240. char data[64];
  241. r = recv (fd, data, sizeof (data), MSG_PEEK);
  242. socket_errno = (r < 0) ? errno : 0;
  243. # endif
  244. if (r == 0)
  245. happened |= POLLHUP;
  246. /* If the event happened on an unconnected server socket,
  247. that's fine. */
  248. else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
  249. happened |= (POLLIN | POLLRDNORM) & sought;
  250. /* Distinguish hung-up sockets from other errors. */
  251. else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
  252. || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
  253. happened |= POLLHUP;
  254. /* some systems can't use recv() on non-socket, including HP NonStop */
  255. else if (socket_errno == ENOTSOCK)
  256. happened |= (POLLIN | POLLRDNORM) & sought;
  257. else
  258. happened |= POLLERR;
  259. }
  260. if (FD_ISSET (fd, wfds))
  261. happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
  262. if (FD_ISSET (fd, efds))
  263. happened |= (POLLPRI | POLLRDBAND) & sought;
  264. return happened;
  265. }
  266. #endif /* !MinGW */
  267. int
  268. poll (struct pollfd *pfd, nfds_t nfd, int timeout)
  269. {
  270. #ifndef WINDOWS_NATIVE
  271. fd_set rfds, wfds, efds;
  272. struct timeval tv;
  273. struct timeval *ptv;
  274. int maxfd, rc;
  275. nfds_t i;
  276. if (nfd < 0)
  277. {
  278. errno = EINVAL;
  279. return -1;
  280. }
  281. /* Don't check directly for NFD too large. Any practical use of a
  282. too-large NFD is caught by one of the other checks below, and
  283. checking directly for getdtablesize is too much of a portability
  284. and/or performance and/or correctness hassle. */
  285. /* EFAULT is not necessary to implement, but let's do it in the
  286. simplest case. */
  287. if (!pfd && nfd)
  288. {
  289. errno = EFAULT;
  290. return -1;
  291. }
  292. /* convert timeout number into a timeval structure */
  293. if (timeout == 0)
  294. {
  295. ptv = &tv;
  296. ptv->tv_sec = 0;
  297. ptv->tv_usec = 0;
  298. }
  299. else if (timeout > 0)
  300. {
  301. ptv = &tv;
  302. ptv->tv_sec = timeout / 1000;
  303. ptv->tv_usec = (timeout % 1000) * 1000;
  304. }
  305. else if (timeout == INFTIM)
  306. /* wait forever */
  307. ptv = NULL;
  308. else
  309. {
  310. errno = EINVAL;
  311. return -1;
  312. }
  313. /* create fd sets and determine max fd */
  314. maxfd = -1;
  315. FD_ZERO (&rfds);
  316. FD_ZERO (&wfds);
  317. FD_ZERO (&efds);
  318. for (i = 0; i < nfd; i++)
  319. {
  320. if (pfd[i].fd < 0)
  321. continue;
  322. if (maxfd < pfd[i].fd)
  323. {
  324. maxfd = pfd[i].fd;
  325. if (FD_SETSIZE <= maxfd)
  326. {
  327. errno = EINVAL;
  328. return -1;
  329. }
  330. }
  331. if (pfd[i].events & (POLLIN | POLLRDNORM))
  332. FD_SET (pfd[i].fd, &rfds);
  333. /* see select(2): "the only exceptional condition detectable
  334. is out-of-band data received on a socket", hence we push
  335. POLLWRBAND events onto wfds instead of efds. */
  336. if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
  337. FD_SET (pfd[i].fd, &wfds);
  338. if (pfd[i].events & (POLLPRI | POLLRDBAND))
  339. FD_SET (pfd[i].fd, &efds);
  340. }
  341. /* examine fd sets */
  342. rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
  343. if (rc < 0)
  344. return rc;
  345. /* establish results */
  346. rc = 0;
  347. for (i = 0; i < nfd; i++)
  348. {
  349. pfd[i].revents = (pfd[i].fd < 0
  350. ? 0
  351. : compute_revents (pfd[i].fd, pfd[i].events,
  352. &rfds, &wfds, &efds));
  353. rc += pfd[i].revents != 0;
  354. }
  355. return rc;
  356. #else
  357. static struct timeval tv0;
  358. static HANDLE hEvent;
  359. WSANETWORKEVENTS ev;
  360. HANDLE h, handle_array[FD_SETSIZE + 2];
  361. DWORD ret, wait_timeout, nhandles;
  362. fd_set rfds, wfds, xfds;
  363. BOOL poll_again;
  364. MSG msg;
  365. int rc = 0;
  366. nfds_t i;
  367. if (nfd < 0 || timeout < -1)
  368. {
  369. errno = EINVAL;
  370. return -1;
  371. }
  372. if (!hEvent)
  373. hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
  374. restart:
  375. handle_array[0] = hEvent;
  376. nhandles = 1;
  377. FD_ZERO (&rfds);
  378. FD_ZERO (&wfds);
  379. FD_ZERO (&xfds);
  380. /* Classify socket handles and create fd sets. */
  381. for (i = 0; i < nfd; i++)
  382. {
  383. int sought = pfd[i].events;
  384. pfd[i].revents = 0;
  385. if (pfd[i].fd < 0)
  386. continue;
  387. if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
  388. | POLLPRI | POLLRDBAND)))
  389. continue;
  390. h = (HANDLE) _get_osfhandle (pfd[i].fd);
  391. assure (h != NULL);
  392. if (IsSocketHandle (h))
  393. {
  394. int requested = FD_CLOSE;
  395. /* see above; socket handles are mapped onto select. */
  396. if (sought & (POLLIN | POLLRDNORM))
  397. {
  398. requested |= FD_READ | FD_ACCEPT;
  399. FD_SET ((SOCKET) h, &rfds);
  400. }
  401. if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
  402. {
  403. requested |= FD_WRITE | FD_CONNECT;
  404. FD_SET ((SOCKET) h, &wfds);
  405. }
  406. if (sought & (POLLPRI | POLLRDBAND))
  407. {
  408. requested |= FD_OOB;
  409. FD_SET ((SOCKET) h, &xfds);
  410. }
  411. if (requested)
  412. WSAEventSelect ((SOCKET) h, hEvent, requested);
  413. }
  414. else
  415. {
  416. /* Poll now. If we get an event, do not poll again. Also,
  417. screen buffer handles are waitable, and they'll block until
  418. a character is available. windows_compute_revents eliminates
  419. bits for the "wrong" direction. */
  420. pfd[i].revents = windows_compute_revents (h, &sought);
  421. if (sought)
  422. handle_array[nhandles++] = h;
  423. if (pfd[i].revents)
  424. timeout = 0;
  425. }
  426. }
  427. if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
  428. {
  429. /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
  430. no need to call select again. */
  431. poll_again = FALSE;
  432. wait_timeout = 0;
  433. }
  434. else
  435. {
  436. poll_again = TRUE;
  437. if (timeout == INFTIM)
  438. wait_timeout = INFINITE;
  439. else
  440. wait_timeout = timeout;
  441. }
  442. for (;;)
  443. {
  444. ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
  445. wait_timeout, QS_ALLINPUT);
  446. if (ret == WAIT_OBJECT_0 + nhandles)
  447. {
  448. /* new input of some other kind */
  449. BOOL bRet;
  450. while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
  451. {
  452. TranslateMessage (&msg);
  453. DispatchMessage (&msg);
  454. }
  455. }
  456. else
  457. break;
  458. }
  459. if (poll_again)
  460. select (0, &rfds, &wfds, &xfds, &tv0);
  461. /* Place a sentinel at the end of the array. */
  462. handle_array[nhandles] = NULL;
  463. nhandles = 1;
  464. for (i = 0; i < nfd; i++)
  465. {
  466. int happened;
  467. if (pfd[i].fd < 0)
  468. continue;
  469. if (!(pfd[i].events & (POLLIN | POLLRDNORM |
  470. POLLOUT | POLLWRNORM | POLLWRBAND)))
  471. continue;
  472. h = (HANDLE) _get_osfhandle (pfd[i].fd);
  473. if (h != handle_array[nhandles])
  474. {
  475. /* It's a socket. */
  476. WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
  477. WSAEventSelect ((SOCKET) h, 0, 0);
  478. /* If we're lucky, WSAEnumNetworkEvents already provided a way
  479. to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
  480. if (FD_ISSET ((SOCKET) h, &rfds)
  481. && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
  482. ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
  483. if (FD_ISSET ((SOCKET) h, &wfds))
  484. ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
  485. if (FD_ISSET ((SOCKET) h, &xfds))
  486. ev.lNetworkEvents |= FD_OOB;
  487. happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events,
  488. ev.lNetworkEvents);
  489. }
  490. else
  491. {
  492. /* Not a socket. */
  493. int sought = pfd[i].events;
  494. happened = windows_compute_revents (h, &sought);
  495. nhandles++;
  496. }
  497. if ((pfd[i].revents |= happened) != 0)
  498. rc++;
  499. }
  500. if (!rc && timeout == INFTIM)
  501. {
  502. SleepEx (1, TRUE);
  503. goto restart;
  504. }
  505. return rc;
  506. #endif
  507. }