This source file includes following definitions.
- IsConsoleHandle
- IsSocketHandle
- windows_poll_handle
- rpl_select
- rpl_select
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include <config.h>
22
23
24 #include <sys/select.h>
25
26 #if defined _WIN32 && ! defined __CYGWIN__
27
28
29 #include <alloca.h>
30 #include <assert.h>
31 #include <sys/types.h>
32 #include <errno.h>
33 #include <limits.h>
34
35 #include <winsock2.h>
36 #include <windows.h>
37 #include <io.h>
38 #include <stdio.h>
39 #include <conio.h>
40 #include <time.h>
41
42
43 #include <sys/time.h>
44
45 #if GNULIB_MSVC_NOTHROW
46 # include "msvc-nothrow.h"
47 #else
48 # include <io.h>
49 #endif
50
51 #undef select
52
53
54 #undef GetModuleHandle
55 #define GetModuleHandle GetModuleHandleA
56 #undef PeekConsoleInput
57 #define PeekConsoleInput PeekConsoleInputA
58 #undef CreateEvent
59 #define CreateEvent CreateEventA
60 #undef PeekMessage
61 #define PeekMessage PeekMessageA
62 #undef DispatchMessage
63 #define DispatchMessage DispatchMessageA
64
65
66 #define GetProcAddress \
67 (void *) GetProcAddress
68
69 struct bitset {
70 unsigned char in[FD_SETSIZE / CHAR_BIT];
71 unsigned char out[FD_SETSIZE / CHAR_BIT];
72 };
73
74
75 typedef struct _FILE_PIPE_LOCAL_INFORMATION {
76 ULONG NamedPipeType;
77 ULONG NamedPipeConfiguration;
78 ULONG MaximumInstances;
79 ULONG CurrentInstances;
80 ULONG InboundQuota;
81 ULONG ReadDataAvailable;
82 ULONG OutboundQuota;
83 ULONG WriteQuotaAvailable;
84 ULONG NamedPipeState;
85 ULONG NamedPipeEnd;
86 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
87
88 typedef struct _IO_STATUS_BLOCK
89 {
90 union {
91 DWORD Status;
92 PVOID Pointer;
93 } u;
94 ULONG_PTR Information;
95 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
96
97 typedef enum _FILE_INFORMATION_CLASS {
98 FilePipeLocalInformation = 24
99 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
100
101 typedef DWORD (WINAPI *PNtQueryInformationFile)
102 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
103
104 #ifndef PIPE_BUF
105 #define PIPE_BUF 512
106 #endif
107
108 static BOOL IsConsoleHandle (HANDLE h)
109 {
110 DWORD mode;
111 return GetConsoleMode (h, &mode) != 0;
112 }
113
114 static BOOL
115 IsSocketHandle (HANDLE h)
116 {
117 WSANETWORKEVENTS ev;
118
119 if (IsConsoleHandle (h))
120 return FALSE;
121
122
123
124 ev.lNetworkEvents = 0xDEADBEEF;
125 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
126 return ev.lNetworkEvents != 0xDEADBEEF;
127 }
128
129
130
131
132 static int
133 windows_poll_handle (HANDLE h, int fd,
134 struct bitset *rbits,
135 struct bitset *wbits,
136 struct bitset *xbits)
137 {
138 BOOL read, write, except;
139 int i, ret;
140 INPUT_RECORD *irbuffer;
141 DWORD avail, nbuffer;
142 BOOL bRet;
143 IO_STATUS_BLOCK iosb;
144 FILE_PIPE_LOCAL_INFORMATION fpli;
145 static PNtQueryInformationFile NtQueryInformationFile;
146 static BOOL once_only;
147
148 read = write = except = FALSE;
149 switch (GetFileType (h))
150 {
151 case FILE_TYPE_DISK:
152 read = TRUE;
153 write = TRUE;
154 break;
155
156 case FILE_TYPE_PIPE:
157 if (!once_only)
158 {
159 NtQueryInformationFile = (PNtQueryInformationFile)
160 GetProcAddress (GetModuleHandle ("ntdll.dll"),
161 "NtQueryInformationFile");
162 once_only = TRUE;
163 }
164
165 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
166 {
167 if (avail)
168 read = TRUE;
169 }
170 else if (GetLastError () == ERROR_BROKEN_PIPE)
171 ;
172
173 else
174 {
175
176
177
178
179
180
181
182
183 memset (&iosb, 0, sizeof (iosb));
184 memset (&fpli, 0, sizeof (fpli));
185
186 if (!NtQueryInformationFile
187 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
188 FilePipeLocalInformation)
189 || fpli.WriteQuotaAvailable >= PIPE_BUF
190 || (fpli.OutboundQuota < PIPE_BUF &&
191 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
192 write = TRUE;
193 }
194 break;
195
196 case FILE_TYPE_CHAR:
197 write = TRUE;
198 if (!(rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
199 break;
200
201 ret = WaitForSingleObject (h, 0);
202 if (ret == WAIT_OBJECT_0)
203 {
204 if (!IsConsoleHandle (h))
205 {
206 read = TRUE;
207 break;
208 }
209
210 nbuffer = avail = 0;
211 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
212
213
214 assert (bRet);
215 if (nbuffer == 0)
216 {
217 except = TRUE;
218 break;
219 }
220
221 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
222 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
223 if (!bRet || avail == 0)
224 {
225 except = TRUE;
226 break;
227 }
228
229 for (i = 0; i < avail; i++)
230 if (irbuffer[i].EventType == KEY_EVENT)
231 read = TRUE;
232 }
233 break;
234
235 default:
236 ret = WaitForSingleObject (h, 0);
237 write = TRUE;
238 if (ret == WAIT_OBJECT_0)
239 read = TRUE;
240
241 break;
242 }
243
244 ret = 0;
245 if (read && (rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
246 {
247 rbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
248 ret++;
249 }
250
251 if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
252 {
253 wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
254 ret++;
255 }
256
257 if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
258 {
259 xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
260 ret++;
261 }
262
263 return ret;
264 }
265
266 int
267 rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
268 struct timeval *timeout)
269 #undef timeval
270 {
271 static struct timeval tv0;
272 static HANDLE hEvent;
273 HANDLE h, handle_array[FD_SETSIZE + 2];
274 fd_set handle_rfds, handle_wfds, handle_xfds;
275 struct bitset rbits, wbits, xbits;
276 unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
277 DWORD ret, wait_timeout, nhandles, nsock, nbuffer;
278 MSG msg;
279 int i, fd, rc;
280 clock_t tend;
281
282 if (nfds > FD_SETSIZE)
283 nfds = FD_SETSIZE;
284
285 if (!timeout)
286 wait_timeout = INFINITE;
287 else
288 {
289 wait_timeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
290
291
292 if (!rfds && !wfds && !xfds)
293 {
294 Sleep (wait_timeout);
295 return 0;
296 }
297 }
298
299 if (!hEvent)
300 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
301
302 handle_array[0] = hEvent;
303 nhandles = 1;
304 nsock = 0;
305
306
307
308
309
310 memset (&rbits, 0, sizeof (rbits));
311 memset (&wbits, 0, sizeof (wbits));
312 memset (&xbits, 0, sizeof (xbits));
313 memset (anyfds_in, 0, sizeof (anyfds_in));
314 if (rfds)
315 for (i = 0; i < rfds->fd_count; i++)
316 {
317 fd = rfds->fd_array[i];
318 h = (HANDLE) _get_osfhandle (fd);
319 if (IsConsoleHandle (h)
320 && !GetNumberOfConsoleInputEvents (h, &nbuffer))
321 continue;
322
323 rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
324 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
325 }
326 else
327 rfds = (fd_set *) alloca (sizeof (fd_set));
328
329 if (wfds)
330 for (i = 0; i < wfds->fd_count; i++)
331 {
332 fd = wfds->fd_array[i];
333 h = (HANDLE) _get_osfhandle (fd);
334 if (IsConsoleHandle (h)
335 && GetNumberOfConsoleInputEvents (h, &nbuffer))
336 continue;
337
338 wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
339 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
340 }
341 else
342 wfds = (fd_set *) alloca (sizeof (fd_set));
343
344 if (xfds)
345 for (i = 0; i < xfds->fd_count; i++)
346 {
347 fd = xfds->fd_array[i];
348 xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
349 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
350 }
351 else
352 xfds = (fd_set *) alloca (sizeof (fd_set));
353
354
355 FD_ZERO (rfds);
356 FD_ZERO (wfds);
357 FD_ZERO (xfds);
358 FD_ZERO (&handle_rfds);
359 FD_ZERO (&handle_wfds);
360 FD_ZERO (&handle_xfds);
361
362
363 for (i = 0; i < nfds; i++)
364 {
365 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
366 continue;
367
368 h = (HANDLE) _get_osfhandle (i);
369 if (!h)
370 {
371 errno = EBADF;
372 return -1;
373 }
374
375 if (IsSocketHandle (h))
376 {
377 int requested = FD_CLOSE;
378
379
380
381 if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
382 {
383 requested |= FD_READ | FD_ACCEPT;
384 FD_SET ((SOCKET) h, rfds);
385 FD_SET ((SOCKET) h, &handle_rfds);
386 }
387 if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
388 {
389 requested |= FD_WRITE | FD_CONNECT;
390 FD_SET ((SOCKET) h, wfds);
391 FD_SET ((SOCKET) h, &handle_wfds);
392 }
393 if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
394 {
395 requested |= FD_OOB;
396 FD_SET ((SOCKET) h, xfds);
397 FD_SET ((SOCKET) h, &handle_xfds);
398 }
399
400 WSAEventSelect ((SOCKET) h, hEvent, requested);
401 nsock++;
402 }
403 else
404 {
405 handle_array[nhandles++] = h;
406
407
408 if (wait_timeout != 0
409 && windows_poll_handle (h, i, &rbits, &wbits, &xbits))
410 wait_timeout = 0;
411 }
412 }
413
414
415 handle_array[nhandles] = NULL;
416
417
418 if (wait_timeout != INFINITE)
419 tend = clock () + wait_timeout;
420
421 restart:
422 if (wait_timeout == 0 || nsock == 0)
423 rc = 0;
424 else
425 {
426
427
428
429 rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
430 if (rc == 0)
431 {
432
433 memcpy (&handle_rfds, rfds, sizeof (fd_set));
434 memcpy (&handle_wfds, wfds, sizeof (fd_set));
435 memcpy (&handle_xfds, xfds, sizeof (fd_set));
436 }
437 else
438 wait_timeout = 0;
439 }
440
441
442 if (wait_timeout != INFINITE)
443 {
444 clock_t tnow = clock ();
445 if (tend >= tnow)
446 wait_timeout = tend - tnow;
447 else
448 wait_timeout = 0;
449 }
450
451 for (;;)
452 {
453 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
454 wait_timeout, QS_ALLINPUT);
455
456 if (ret == WAIT_OBJECT_0 + nhandles)
457 {
458
459 BOOL bRet;
460 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
461 {
462 TranslateMessage (&msg);
463 DispatchMessage (&msg);
464 }
465 }
466 else
467 break;
468 }
469
470
471 if (rc == 0 && nsock > 0)
472 rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
473
474 if (nhandles > 1)
475 {
476
477 nhandles = 1;
478 for (i = 0; i < nfds; i++)
479 {
480 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
481 continue;
482
483 h = (HANDLE) _get_osfhandle (i);
484 if (h == handle_array[nhandles])
485 {
486
487 nhandles++;
488 windows_poll_handle (h, i, &rbits, &wbits, &xbits);
489 if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
490 || wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
491 || xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
492 rc++;
493 }
494 }
495
496 if (rc == 0
497 && (wait_timeout == INFINITE
498
499
500
501
502
503
504
505 || (wait_timeout != 0 && nhandles > 1)))
506 {
507
508
509 memcpy (&handle_rfds, rfds, sizeof (fd_set));
510 memcpy (&handle_wfds, wfds, sizeof (fd_set));
511 memcpy (&handle_xfds, xfds, sizeof (fd_set));
512 SleepEx (1, TRUE);
513 goto restart;
514 }
515 if (timeout && wait_timeout == 0 && rc == 0)
516 timeout->tv_sec = timeout->tv_usec = 0;
517 }
518
519
520 FD_ZERO (rfds);
521 FD_ZERO (wfds);
522 FD_ZERO (xfds);
523 nhandles = 1;
524 for (i = 0; i < nfds; i++)
525 {
526 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
527 continue;
528
529 h = (HANDLE) _get_osfhandle (i);
530 if (h != handle_array[nhandles])
531 {
532
533 SOCKET s = (SOCKET) h;
534 WSAEventSelect (s, NULL, 0);
535 if (FD_ISSET (s, &handle_rfds))
536 FD_SET (i, rfds);
537 if (FD_ISSET (s, &handle_wfds))
538 FD_SET (i, wfds);
539 if (FD_ISSET (s, &handle_xfds))
540 FD_SET (i, xfds);
541 }
542 else
543 {
544
545 nhandles++;
546 if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
547 FD_SET (i, rfds);
548 if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
549 FD_SET (i, wfds);
550 if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
551 FD_SET (i, xfds);
552 }
553 }
554
555 return rc;
556 }
557
558 #else
559
560 #include <stddef.h>
561 #include <errno.h>
562 #include <unistd.h>
563
564 #undef select
565
566 int
567 rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
568 struct timeval *timeout)
569 {
570 int i;
571
572
573 if (nfds < 0 || nfds > FD_SETSIZE)
574 {
575 errno = EINVAL;
576 return -1;
577 }
578 for (i = 0; i < nfds; i++)
579 {
580 if (((rfds && FD_ISSET (i, rfds))
581 || (wfds && FD_ISSET (i, wfds))
582 || (xfds && FD_ISSET (i, xfds)))
583 && dup2 (i, i) != i)
584 return -1;
585 }
586
587
588 if (nfds == 0)
589 {
590 nfds = 1;
591 rfds = NULL;
592 wfds = NULL;
593 xfds = NULL;
594 }
595 return select (nfds, rfds, wfds, xfds, timeout);
596 }
597
598 #endif