defsubst
[bpt/guile.git] / lib / select.c
1 /* Emulation for select(2)
2 Contributed by Paolo Bonzini.
3
4 Copyright 2008-2014 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 Lesser 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 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License along
19 with this program; if not, see <http://www.gnu.org/licenses/>. */
20
21 #include <config.h>
22 #include <alloca.h>
23 #include <assert.h>
24
25 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
26 /* Native Windows. */
27
28 #include <sys/types.h>
29 #include <errno.h>
30 #include <limits.h>
31
32 #include <winsock2.h>
33 #include <windows.h>
34 #include <io.h>
35 #include <stdio.h>
36 #include <conio.h>
37 #include <time.h>
38
39 /* Get the overridden 'struct timeval'. */
40 #include <sys/time.h>
41
42 #include "msvc-nothrow.h"
43
44 #undef select
45
46 struct bitset {
47 unsigned char in[FD_SETSIZE / CHAR_BIT];
48 unsigned char out[FD_SETSIZE / CHAR_BIT];
49 };
50
51 /* Declare data structures for ntdll functions. */
52 typedef struct _FILE_PIPE_LOCAL_INFORMATION {
53 ULONG NamedPipeType;
54 ULONG NamedPipeConfiguration;
55 ULONG MaximumInstances;
56 ULONG CurrentInstances;
57 ULONG InboundQuota;
58 ULONG ReadDataAvailable;
59 ULONG OutboundQuota;
60 ULONG WriteQuotaAvailable;
61 ULONG NamedPipeState;
62 ULONG NamedPipeEnd;
63 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
64
65 typedef struct _IO_STATUS_BLOCK
66 {
67 union {
68 DWORD Status;
69 PVOID Pointer;
70 } u;
71 ULONG_PTR Information;
72 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
73
74 typedef enum _FILE_INFORMATION_CLASS {
75 FilePipeLocalInformation = 24
76 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
77
78 typedef DWORD (WINAPI *PNtQueryInformationFile)
79 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
80
81 #ifndef PIPE_BUF
82 #define PIPE_BUF 512
83 #endif
84
85 /* Optimized test whether a HANDLE refers to a console.
86 See <http://lists.gnu.org/archive/html/bug-gnulib/2009-08/msg00065.html>. */
87 #define IsConsoleHandle(h) (((intptr_t) (h) & 3) == 3)
88
89 static BOOL
90 IsSocketHandle (HANDLE h)
91 {
92 WSANETWORKEVENTS ev;
93
94 if (IsConsoleHandle (h))
95 return FALSE;
96
97 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
98 WSAEnumNetworkEvents instead distinguishes the two correctly. */
99 ev.lNetworkEvents = 0xDEADBEEF;
100 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
101 return ev.lNetworkEvents != 0xDEADBEEF;
102 }
103
104 /* Compute output fd_sets for libc descriptor FD (whose Windows handle is
105 H). */
106
107 static int
108 windows_poll_handle (HANDLE h, int fd,
109 struct bitset *rbits,
110 struct bitset *wbits,
111 struct bitset *xbits)
112 {
113 BOOL read, write, except;
114 int i, ret;
115 INPUT_RECORD *irbuffer;
116 DWORD avail, nbuffer;
117 BOOL bRet;
118 IO_STATUS_BLOCK iosb;
119 FILE_PIPE_LOCAL_INFORMATION fpli;
120 static PNtQueryInformationFile NtQueryInformationFile;
121 static BOOL once_only;
122
123 read = write = except = FALSE;
124 switch (GetFileType (h))
125 {
126 case FILE_TYPE_DISK:
127 read = TRUE;
128 write = TRUE;
129 break;
130
131 case FILE_TYPE_PIPE:
132 if (!once_only)
133 {
134 NtQueryInformationFile = (PNtQueryInformationFile)
135 GetProcAddress (GetModuleHandle ("ntdll.dll"),
136 "NtQueryInformationFile");
137 once_only = TRUE;
138 }
139
140 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
141 {
142 if (avail)
143 read = TRUE;
144 }
145 else if (GetLastError () == ERROR_BROKEN_PIPE)
146 ;
147
148 else
149 {
150 /* It was the write-end of the pipe. Check if it is writable.
151 If NtQueryInformationFile fails, optimistically assume the pipe is
152 writable. This could happen on Windows 9x, where
153 NtQueryInformationFile is not available, or if we inherit a pipe
154 that doesn't permit FILE_READ_ATTRIBUTES access on the write end
155 (I think this should not happen since Windows XP SP2; WINE seems
156 fine too). Otherwise, ensure that enough space is available for
157 atomic writes. */
158 memset (&iosb, 0, sizeof (iosb));
159 memset (&fpli, 0, sizeof (fpli));
160
161 if (!NtQueryInformationFile
162 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
163 FilePipeLocalInformation)
164 || fpli.WriteQuotaAvailable >= PIPE_BUF
165 || (fpli.OutboundQuota < PIPE_BUF &&
166 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
167 write = TRUE;
168 }
169 break;
170
171 case FILE_TYPE_CHAR:
172 write = TRUE;
173 if (!(rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
174 break;
175
176 ret = WaitForSingleObject (h, 0);
177 if (ret == WAIT_OBJECT_0)
178 {
179 if (!IsConsoleHandle (h))
180 {
181 read = TRUE;
182 break;
183 }
184
185 nbuffer = avail = 0;
186 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
187
188 /* Screen buffers handles are filtered earlier. */
189 assert (bRet);
190 if (nbuffer == 0)
191 {
192 except = TRUE;
193 break;
194 }
195
196 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
197 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
198 if (!bRet || avail == 0)
199 {
200 except = TRUE;
201 break;
202 }
203
204 for (i = 0; i < avail; i++)
205 if (irbuffer[i].EventType == KEY_EVENT)
206 read = TRUE;
207 }
208 break;
209
210 default:
211 ret = WaitForSingleObject (h, 0);
212 write = TRUE;
213 if (ret == WAIT_OBJECT_0)
214 read = TRUE;
215
216 break;
217 }
218
219 ret = 0;
220 if (read && (rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
221 {
222 rbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
223 ret++;
224 }
225
226 if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
227 {
228 wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
229 ret++;
230 }
231
232 if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
233 {
234 xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
235 ret++;
236 }
237
238 return ret;
239 }
240
241 int
242 rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
243 struct timeval *timeout)
244 #undef timeval
245 {
246 static struct timeval tv0;
247 static HANDLE hEvent;
248 HANDLE h, handle_array[FD_SETSIZE + 2];
249 fd_set handle_rfds, handle_wfds, handle_xfds;
250 struct bitset rbits, wbits, xbits;
251 unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
252 DWORD ret, wait_timeout, nhandles, nsock, nbuffer;
253 MSG msg;
254 int i, fd, rc;
255
256 if (nfds > FD_SETSIZE)
257 nfds = FD_SETSIZE;
258
259 if (!timeout)
260 wait_timeout = INFINITE;
261 else
262 {
263 wait_timeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
264
265 /* select is also used as a portable usleep. */
266 if (!rfds && !wfds && !xfds)
267 {
268 Sleep (wait_timeout);
269 return 0;
270 }
271 }
272
273 if (!hEvent)
274 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
275
276 handle_array[0] = hEvent;
277 nhandles = 1;
278 nsock = 0;
279
280 /* Copy descriptors to bitsets. At the same time, eliminate
281 bits in the "wrong" direction for console input buffers
282 and screen buffers, because screen buffers are waitable
283 and they will block until a character is available. */
284 memset (&rbits, 0, sizeof (rbits));
285 memset (&wbits, 0, sizeof (wbits));
286 memset (&xbits, 0, sizeof (xbits));
287 memset (anyfds_in, 0, sizeof (anyfds_in));
288 if (rfds)
289 for (i = 0; i < rfds->fd_count; i++)
290 {
291 fd = rfds->fd_array[i];
292 h = (HANDLE) _get_osfhandle (fd);
293 if (IsConsoleHandle (h)
294 && !GetNumberOfConsoleInputEvents (h, &nbuffer))
295 continue;
296
297 rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
298 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
299 }
300 else
301 rfds = (fd_set *) alloca (sizeof (fd_set));
302
303 if (wfds)
304 for (i = 0; i < wfds->fd_count; i++)
305 {
306 fd = wfds->fd_array[i];
307 h = (HANDLE) _get_osfhandle (fd);
308 if (IsConsoleHandle (h)
309 && GetNumberOfConsoleInputEvents (h, &nbuffer))
310 continue;
311
312 wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
313 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
314 }
315 else
316 wfds = (fd_set *) alloca (sizeof (fd_set));
317
318 if (xfds)
319 for (i = 0; i < xfds->fd_count; i++)
320 {
321 fd = xfds->fd_array[i];
322 xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
323 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
324 }
325 else
326 xfds = (fd_set *) alloca (sizeof (fd_set));
327
328 /* Zero all the fd_sets, including the application's. */
329 FD_ZERO (rfds);
330 FD_ZERO (wfds);
331 FD_ZERO (xfds);
332 FD_ZERO (&handle_rfds);
333 FD_ZERO (&handle_wfds);
334 FD_ZERO (&handle_xfds);
335
336 /* Classify handles. Create fd sets for sockets, poll the others. */
337 for (i = 0; i < nfds; i++)
338 {
339 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
340 continue;
341
342 h = (HANDLE) _get_osfhandle (i);
343 if (!h)
344 {
345 errno = EBADF;
346 return -1;
347 }
348
349 if (IsSocketHandle (h))
350 {
351 int requested = FD_CLOSE;
352
353 /* See above; socket handles are mapped onto select, but we
354 need to map descriptors to handles. */
355 if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
356 {
357 requested |= FD_READ | FD_ACCEPT;
358 FD_SET ((SOCKET) h, rfds);
359 FD_SET ((SOCKET) h, &handle_rfds);
360 }
361 if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
362 {
363 requested |= FD_WRITE | FD_CONNECT;
364 FD_SET ((SOCKET) h, wfds);
365 FD_SET ((SOCKET) h, &handle_wfds);
366 }
367 if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
368 {
369 requested |= FD_OOB;
370 FD_SET ((SOCKET) h, xfds);
371 FD_SET ((SOCKET) h, &handle_xfds);
372 }
373
374 WSAEventSelect ((SOCKET) h, hEvent, requested);
375 nsock++;
376 }
377 else
378 {
379 handle_array[nhandles++] = h;
380
381 /* Poll now. If we get an event, do not wait below. */
382 if (wait_timeout != 0
383 && windows_poll_handle (h, i, &rbits, &wbits, &xbits))
384 wait_timeout = 0;
385 }
386 }
387
388 /* Place a sentinel at the end of the array. */
389 handle_array[nhandles] = NULL;
390
391 restart:
392 if (wait_timeout == 0 || nsock == 0)
393 rc = 0;
394 else
395 {
396 /* See if we need to wait in the loop below. If any select is ready,
397 do MsgWaitForMultipleObjects anyway to dispatch messages, but
398 no need to call select again. */
399 rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
400 if (rc == 0)
401 {
402 /* Restore the fd_sets for the other select we do below. */
403 memcpy (&handle_rfds, rfds, sizeof (fd_set));
404 memcpy (&handle_wfds, wfds, sizeof (fd_set));
405 memcpy (&handle_xfds, xfds, sizeof (fd_set));
406 }
407 else
408 wait_timeout = 0;
409 }
410
411 for (;;)
412 {
413 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
414 wait_timeout, QS_ALLINPUT);
415
416 if (ret == WAIT_OBJECT_0 + nhandles)
417 {
418 /* new input of some other kind */
419 BOOL bRet;
420 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
421 {
422 TranslateMessage (&msg);
423 DispatchMessage (&msg);
424 }
425 }
426 else
427 break;
428 }
429
430 /* If we haven't done it yet, check the status of the sockets. */
431 if (rc == 0 && nsock > 0)
432 rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
433
434 if (nhandles > 1)
435 {
436 /* Count results that are not counted in the return value of select. */
437 nhandles = 1;
438 for (i = 0; i < nfds; i++)
439 {
440 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
441 continue;
442
443 h = (HANDLE) _get_osfhandle (i);
444 if (h == handle_array[nhandles])
445 {
446 /* Not a socket. */
447 nhandles++;
448 windows_poll_handle (h, i, &rbits, &wbits, &xbits);
449 if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
450 || wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
451 || xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
452 rc++;
453 }
454 }
455
456 if (rc == 0 && wait_timeout == INFINITE)
457 {
458 /* Sleep 1 millisecond to avoid busy wait and retry with the
459 original fd_sets. */
460 memcpy (&handle_rfds, rfds, sizeof (fd_set));
461 memcpy (&handle_wfds, wfds, sizeof (fd_set));
462 memcpy (&handle_xfds, xfds, sizeof (fd_set));
463 SleepEx (1, TRUE);
464 goto restart;
465 }
466 }
467
468 /* Now fill in the results. */
469 FD_ZERO (rfds);
470 FD_ZERO (wfds);
471 FD_ZERO (xfds);
472 nhandles = 1;
473 for (i = 0; i < nfds; i++)
474 {
475 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
476 continue;
477
478 h = (HANDLE) _get_osfhandle (i);
479 if (h != handle_array[nhandles])
480 {
481 /* Perform handle->descriptor mapping. */
482 WSAEventSelect ((SOCKET) h, NULL, 0);
483 if (FD_ISSET (h, &handle_rfds))
484 FD_SET (i, rfds);
485 if (FD_ISSET (h, &handle_wfds))
486 FD_SET (i, wfds);
487 if (FD_ISSET (h, &handle_xfds))
488 FD_SET (i, xfds);
489 }
490 else
491 {
492 /* Not a socket. */
493 nhandles++;
494 if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
495 FD_SET (i, rfds);
496 if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
497 FD_SET (i, wfds);
498 if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
499 FD_SET (i, xfds);
500 }
501 }
502
503 return rc;
504 }
505
506 #else /* ! Native Windows. */
507
508 #include <sys/select.h>
509 #include <stddef.h> /* NULL */
510 #include <errno.h>
511 #include <unistd.h>
512
513 #undef select
514
515 int
516 rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
517 struct timeval *timeout)
518 {
519 int i;
520
521 /* FreeBSD 8.2 has a bug: it does not always detect invalid fds. */
522 if (nfds < 0 || nfds > FD_SETSIZE)
523 {
524 errno = EINVAL;
525 return -1;
526 }
527 for (i = 0; i < nfds; i++)
528 {
529 if (((rfds && FD_ISSET (i, rfds))
530 || (wfds && FD_ISSET (i, wfds))
531 || (xfds && FD_ISSET (i, xfds)))
532 && dup2 (i, i) != i)
533 return -1;
534 }
535
536 /* Interix 3.5 has a bug: it does not support nfds == 0. */
537 if (nfds == 0)
538 {
539 nfds = 1;
540 rfds = NULL;
541 wfds = NULL;
542 xfds = NULL;
543 }
544 return select (nfds, rfds, wfds, xfds, timeout);
545 }
546
547 #endif