1 /* Emulation for select(2)
2 Contributed by Paolo Bonzini.
4 Copyright 2008-2011 Free Software Foundation, Inc.
6 This file is part of gnulib.
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 3, or (at your option)
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.
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation,
20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
26 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
29 #include <sys/types.h>
42 unsigned char in
[FD_SETSIZE
/ CHAR_BIT
];
43 unsigned char out
[FD_SETSIZE
/ CHAR_BIT
];
46 /* Declare data structures for ntdll functions. */
47 typedef struct _FILE_PIPE_LOCAL_INFORMATION
{
49 ULONG NamedPipeConfiguration
;
50 ULONG MaximumInstances
;
51 ULONG CurrentInstances
;
53 ULONG ReadDataAvailable
;
55 ULONG WriteQuotaAvailable
;
58 } FILE_PIPE_LOCAL_INFORMATION
, *PFILE_PIPE_LOCAL_INFORMATION
;
60 typedef struct _IO_STATUS_BLOCK
66 ULONG_PTR Information
;
67 } IO_STATUS_BLOCK
, *PIO_STATUS_BLOCK
;
69 typedef enum _FILE_INFORMATION_CLASS
{
70 FilePipeLocalInformation
= 24
71 } FILE_INFORMATION_CLASS
, *PFILE_INFORMATION_CLASS
;
73 typedef DWORD (WINAPI
*PNtQueryInformationFile
)
74 (HANDLE
, IO_STATUS_BLOCK
*, VOID
*, ULONG
, FILE_INFORMATION_CLASS
);
80 #define IsConsoleHandle(h) (((long) (h) & 3) == 3)
83 IsSocketHandle (HANDLE h
)
87 if (IsConsoleHandle (h
))
90 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
91 WSAEnumNetworkEvents instead distinguishes the two correctly. */
92 ev
.lNetworkEvents
= 0xDEADBEEF;
93 WSAEnumNetworkEvents ((SOCKET
) h
, NULL
, &ev
);
94 return ev
.lNetworkEvents
!= 0xDEADBEEF;
97 /* Compute output fd_sets for libc descriptor FD (whose Win32 handle is H). */
100 win32_poll_handle (HANDLE h
, int fd
, struct bitset
*rbits
, struct bitset
*wbits
,
101 struct bitset
*xbits
)
103 BOOL read
, write
, except
;
105 INPUT_RECORD
*irbuffer
;
106 DWORD avail
, nbuffer
;
108 IO_STATUS_BLOCK iosb
;
109 FILE_PIPE_LOCAL_INFORMATION fpli
;
110 static PNtQueryInformationFile NtQueryInformationFile
;
111 static BOOL once_only
;
113 read
= write
= except
= FALSE
;
114 switch (GetFileType (h
))
124 NtQueryInformationFile
= (PNtQueryInformationFile
)
125 GetProcAddress (GetModuleHandle ("ntdll.dll"),
126 "NtQueryInformationFile");
130 if (PeekNamedPipe (h
, NULL
, 0, NULL
, &avail
, NULL
) != 0)
135 else if (GetLastError () == ERROR_BROKEN_PIPE
)
140 /* It was the write-end of the pipe. Check if it is writable.
141 If NtQueryInformationFile fails, optimistically assume the pipe is
142 writable. This could happen on Win9x, where NtQueryInformationFile
143 is not available, or if we inherit a pipe that doesn't permit
144 FILE_READ_ATTRIBUTES access on the write end (I think this should
145 not happen since WinXP SP2; WINE seems fine too). Otherwise,
146 ensure that enough space is available for atomic writes. */
147 memset (&iosb
, 0, sizeof (iosb
));
148 memset (&fpli
, 0, sizeof (fpli
));
150 if (!NtQueryInformationFile
151 || NtQueryInformationFile (h
, &iosb
, &fpli
, sizeof (fpli
),
152 FilePipeLocalInformation
)
153 || fpli
.WriteQuotaAvailable
>= PIPE_BUF
154 || (fpli
.OutboundQuota
< PIPE_BUF
&&
155 fpli
.WriteQuotaAvailable
== fpli
.OutboundQuota
))
162 if (!(rbits
->in
[fd
/ CHAR_BIT
] & (1 << (fd
& (CHAR_BIT
- 1)))))
165 ret
= WaitForSingleObject (h
, 0);
166 if (ret
== WAIT_OBJECT_0
)
168 if (!IsConsoleHandle (h
))
175 bRet
= GetNumberOfConsoleInputEvents (h
, &nbuffer
);
177 /* Screen buffers handles are filtered earlier. */
185 irbuffer
= (INPUT_RECORD
*) alloca (nbuffer
* sizeof (INPUT_RECORD
));
186 bRet
= PeekConsoleInput (h
, irbuffer
, nbuffer
, &avail
);
187 if (!bRet
|| avail
== 0)
193 for (i
= 0; i
< avail
; i
++)
194 if (irbuffer
[i
].EventType
== KEY_EVENT
)
200 ret
= WaitForSingleObject (h
, 0);
202 if (ret
== WAIT_OBJECT_0
)
209 if (read
&& (rbits
->in
[fd
/ CHAR_BIT
] & (1 << (fd
& (CHAR_BIT
- 1)))))
211 rbits
->out
[fd
/ CHAR_BIT
] |= (1 << (fd
& (CHAR_BIT
- 1)));
215 if (write
&& (wbits
->in
[fd
/ CHAR_BIT
] & (1 << (fd
& (CHAR_BIT
- 1)))))
217 wbits
->out
[fd
/ CHAR_BIT
] |= (1 << (fd
& (CHAR_BIT
- 1)));
221 if (except
&& (xbits
->in
[fd
/ CHAR_BIT
] & (1 << (fd
& (CHAR_BIT
- 1)))))
223 xbits
->out
[fd
/ CHAR_BIT
] |= (1 << (fd
& (CHAR_BIT
- 1)));
231 rpl_select (int nfds
, fd_set
*rfds
, fd_set
*wfds
, fd_set
*xfds
,
232 struct timeval
*timeout
)
234 static struct timeval tv0
;
235 static HANDLE hEvent
;
236 HANDLE h
, handle_array
[FD_SETSIZE
+ 2];
237 fd_set handle_rfds
, handle_wfds
, handle_xfds
;
238 struct bitset rbits
, wbits
, xbits
;
239 unsigned char anyfds_in
[FD_SETSIZE
/ CHAR_BIT
];
240 DWORD ret
, wait_timeout
, nhandles
, nsock
, nbuffer
;
244 if (nfds
> FD_SETSIZE
)
248 wait_timeout
= INFINITE
;
251 wait_timeout
= timeout
->tv_sec
* 1000 + timeout
->tv_usec
/ 1000;
253 /* select is also used as a portable usleep. */
254 if (!rfds
&& !wfds
&& !xfds
)
256 Sleep (wait_timeout
);
262 hEvent
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
264 handle_array
[0] = hEvent
;
268 /* Copy descriptors to bitsets. At the same time, eliminate
269 bits in the "wrong" direction for console input buffers
270 and screen buffers, because screen buffers are waitable
271 and they will block until a character is available. */
272 memset (&rbits
, 0, sizeof (rbits
));
273 memset (&wbits
, 0, sizeof (wbits
));
274 memset (&xbits
, 0, sizeof (xbits
));
275 memset (anyfds_in
, 0, sizeof (anyfds_in
));
277 for (i
= 0; i
< rfds
->fd_count
; i
++)
279 fd
= rfds
->fd_array
[i
];
280 h
= (HANDLE
) _get_osfhandle (fd
);
281 if (IsConsoleHandle (h
)
282 && !GetNumberOfConsoleInputEvents (h
, &nbuffer
))
285 rbits
.in
[fd
/ CHAR_BIT
] |= 1 << (fd
& (CHAR_BIT
- 1));
286 anyfds_in
[fd
/ CHAR_BIT
] |= 1 << (fd
& (CHAR_BIT
- 1));
289 rfds
= (fd_set
*) alloca (sizeof (fd_set
));
292 for (i
= 0; i
< wfds
->fd_count
; i
++)
294 fd
= wfds
->fd_array
[i
];
295 h
= (HANDLE
) _get_osfhandle (fd
);
296 if (IsConsoleHandle (h
)
297 && GetNumberOfConsoleInputEvents (h
, &nbuffer
))
300 wbits
.in
[fd
/ CHAR_BIT
] |= 1 << (fd
& (CHAR_BIT
- 1));
301 anyfds_in
[fd
/ CHAR_BIT
] |= 1 << (fd
& (CHAR_BIT
- 1));
304 wfds
= (fd_set
*) alloca (sizeof (fd_set
));
307 for (i
= 0; i
< xfds
->fd_count
; i
++)
309 fd
= xfds
->fd_array
[i
];
310 xbits
.in
[fd
/ CHAR_BIT
] |= 1 << (fd
& (CHAR_BIT
- 1));
311 anyfds_in
[fd
/ CHAR_BIT
] |= 1 << (fd
& (CHAR_BIT
- 1));
314 xfds
= (fd_set
*) alloca (sizeof (fd_set
));
316 /* Zero all the fd_sets, including the application's. */
320 FD_ZERO (&handle_rfds
);
321 FD_ZERO (&handle_wfds
);
322 FD_ZERO (&handle_xfds
);
324 /* Classify handles. Create fd sets for sockets, poll the others. */
325 for (i
= 0; i
< nfds
; i
++)
327 if ((anyfds_in
[i
/ CHAR_BIT
] & (1 << (i
& (CHAR_BIT
- 1)))) == 0)
330 h
= (HANDLE
) _get_osfhandle (i
);
337 if (IsSocketHandle (h
))
339 int requested
= FD_CLOSE
;
341 /* See above; socket handles are mapped onto select, but we
342 need to map descriptors to handles. */
343 if (rbits
.in
[i
/ CHAR_BIT
] & (1 << (i
& (CHAR_BIT
- 1))))
345 requested
|= FD_READ
| FD_ACCEPT
;
346 FD_SET ((SOCKET
) h
, rfds
);
347 FD_SET ((SOCKET
) h
, &handle_rfds
);
349 if (wbits
.in
[i
/ CHAR_BIT
] & (1 << (i
& (CHAR_BIT
- 1))))
351 requested
|= FD_WRITE
| FD_CONNECT
;
352 FD_SET ((SOCKET
) h
, wfds
);
353 FD_SET ((SOCKET
) h
, &handle_wfds
);
355 if (xbits
.in
[i
/ CHAR_BIT
] & (1 << (i
& (CHAR_BIT
- 1))))
358 FD_SET ((SOCKET
) h
, xfds
);
359 FD_SET ((SOCKET
) h
, &handle_xfds
);
362 WSAEventSelect ((SOCKET
) h
, hEvent
, requested
);
367 handle_array
[nhandles
++] = h
;
369 /* Poll now. If we get an event, do not wait below. */
370 if (wait_timeout
!= 0
371 && win32_poll_handle (h
, i
, &rbits
, &wbits
, &xbits
))
376 if (wait_timeout
== 0 || nsock
== 0)
380 /* See if we need to wait in the loop below. If any select is ready,
381 do MsgWaitForMultipleObjects anyway to dispatch messages, but
382 no need to call select again. */
383 rc
= select (0, &handle_rfds
, &handle_wfds
, &handle_xfds
, &tv0
);
386 /* Restore the fd_sets for the other select we do below. */
387 memcpy (&handle_rfds
, rfds
, sizeof (fd_set
));
388 memcpy (&handle_wfds
, wfds
, sizeof (fd_set
));
389 memcpy (&handle_xfds
, xfds
, sizeof (fd_set
));
397 ret
= MsgWaitForMultipleObjects (nhandles
, handle_array
, FALSE
,
398 wait_timeout
, QS_ALLINPUT
);
400 if (ret
== WAIT_OBJECT_0
+ nhandles
)
402 /* new input of some other kind */
404 while ((bRet
= PeekMessage (&msg
, NULL
, 0, 0, PM_REMOVE
)) != 0)
406 TranslateMessage (&msg
);
407 DispatchMessage (&msg
);
414 /* If we haven't done it yet, check the status of the sockets. */
415 if (rc
== 0 && nsock
> 0)
416 rc
= select (0, &handle_rfds
, &handle_wfds
, &handle_xfds
, &tv0
);
418 /* Now fill in the results. */
423 /* Place a sentinel at the end of the array. */
424 handle_array
[nhandles
] = NULL
;
426 for (i
= 0; i
< nfds
; i
++)
428 if ((anyfds_in
[i
/ CHAR_BIT
] & (1 << (i
& (CHAR_BIT
- 1)))) == 0)
431 h
= (HANDLE
) _get_osfhandle (i
);
432 if (h
!= handle_array
[nhandles
])
434 /* Perform handle->descriptor mapping. Don't update rc, as these
435 results are counted in the return value of Winsock's select. */
436 WSAEventSelect ((SOCKET
) h
, NULL
, 0);
437 if (FD_ISSET (h
, &handle_rfds
))
439 if (FD_ISSET (h
, &handle_wfds
))
441 if (FD_ISSET (h
, &handle_xfds
))
448 win32_poll_handle (h
, i
, &rbits
, &wbits
, &xbits
);
449 if (rbits
.out
[i
/ CHAR_BIT
] & (1 << (i
& (CHAR_BIT
- 1))))
454 if (wbits
.out
[i
/ CHAR_BIT
] & (1 << (i
& (CHAR_BIT
- 1))))
459 if (xbits
.out
[i
/ CHAR_BIT
] & (1 << (i
& (CHAR_BIT
- 1))))
470 #else /* ! Native Win32. */
472 #include <sys/select.h>
477 rpl_select (int nfds
, fd_set
*rfds
, fd_set
*wfds
, fd_set
*xfds
,
478 struct timeval
*timeout
)
480 /* Interix 3.5 has a bug: it does not support nfds == 0. */
488 return select (nfds
, rfds
, wfds
, xfds
, timeout
);