1 /* Emulation for select(2)
2 Contributed by Paolo Bonzini.
4 Copyright 2008 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 2, 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. */
25 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
26 #include <sys/types.h>
39 unsigned char in[FD_SETSIZE / CHAR_BIT];
40 unsigned char out[FD_SETSIZE / CHAR_BIT];
43 /* Declare data structures for ntdll functions. */
44 typedef struct _FILE_PIPE_LOCAL_INFORMATION {
46 ULONG NamedPipeConfiguration;
47 ULONG MaximumInstances;
48 ULONG CurrentInstances;
50 ULONG ReadDataAvailable;
52 ULONG WriteQuotaAvailable;
55 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
57 typedef struct _IO_STATUS_BLOCK
63 ULONG_PTR Information;
64 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
66 typedef enum _FILE_INFORMATION_CLASS {
67 FilePipeLocalInformation = 24
68 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
70 typedef DWORD (WINAPI *PNtQueryInformationFile)
71 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
77 /* Compute output fd_sets for libc descriptor FD (whose Win32 handle is H). */
80 win32_poll_handle (HANDLE h, int fd, struct bitset *rbits, struct bitset *wbits,
83 BOOL read, write, except;
85 INPUT_RECORD *irbuffer;
89 FILE_PIPE_LOCAL_INFORMATION fpli;
90 static PNtQueryInformationFile NtQueryInformationFile;
91 static BOOL once_only;
93 read = write = except = FALSE;
94 switch (GetFileType (h))
99 NtQueryInformationFile = (PNtQueryInformationFile)
100 GetProcAddress (GetModuleHandle ("ntdll.dll"),
101 "NtQueryInformationFile");
105 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
113 /* It was the write-end of the pipe. Check if it is writable.
114 If NtQueryInformationFile fails, optimistically assume the pipe is
115 writable. This could happen on Win9x, where NtQueryInformationFile
116 is not available, or if we inherit a pipe that doesn't permit
117 FILE_READ_ATTRIBUTES access on the write end (I think this should
118 not happen since WinXP SP2; WINE seems fine too). Otherwise,
119 ensure that enough space is available for atomic writes. */
120 memset (&iosb, 0, sizeof (iosb));
121 memset (&fpli, 0, sizeof (fpli));
123 if (!NtQueryInformationFile
124 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
125 FilePipeLocalInformation)
126 || fpli.WriteQuotaAvailable >= PIPE_BUF
127 || (fpli.OutboundQuota < PIPE_BUF &&
128 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
134 ret = WaitForSingleObject (h, 0);
136 if (ret == WAIT_OBJECT_0)
139 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
140 if (!bRet || nbuffer == 0)
143 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
144 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
145 if (!bRet || avail == 0)
148 for (i = 0; i < avail; i++)
149 if (irbuffer[i].EventType == KEY_EVENT)
155 ret = WaitForSingleObject (h, 0);
157 if (ret == WAIT_OBJECT_0)
164 if (read && (rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
166 rbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
170 if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
172 wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
176 if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
178 xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
186 rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
187 struct timeval *timeout)
189 static struct timeval tv0;
190 static HANDLE hEvent;
191 HANDLE h, handle_array[FD_SETSIZE + 2];
192 fd_set handle_rfds, handle_wfds, handle_xfds;
193 struct bitset rbits, wbits, xbits;
194 unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
195 DWORD ret, wait_timeout, nhandles, nsock;
199 if (nfds > FD_SETSIZE)
203 wait_timeout = INFINITE;
206 wait_timeout = timeout->tv_sec + timeout->tv_usec / 1000;
208 /* select is also used as a portable usleep. */
209 if (!rfds && !wfds && !xfds)
211 Sleep (wait_timeout);
217 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
219 handle_array[0] = hEvent;
223 /* Copy descriptors to bitsets. */
224 memset (&rbits, 0, sizeof (rbits));
225 memset (&wbits, 0, sizeof (wbits));
226 memset (&xbits, 0, sizeof (xbits));
227 memset (anyfds_in, 0, sizeof (anyfds_in));
229 for (i = 0; i < rfds->fd_count; i++)
231 fd = rfds->fd_array[i];
232 rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
233 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
236 rfds = (fd_set *) alloca (sizeof (fd_set));
239 for (i = 0; i < wfds->fd_count; i++)
241 fd = wfds->fd_array[i];
242 wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
243 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
246 wfds = (fd_set *) alloca (sizeof (fd_set));
249 for (i = 0; i < xfds->fd_count; i++)
251 fd = xfds->fd_array[i];
252 xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
253 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
256 xfds = (fd_set *) alloca (sizeof (fd_set));
258 /* Zero all the fd_sets, including the application's. */
262 FD_ZERO (&handle_rfds);
263 FD_ZERO (&handle_wfds);
264 FD_ZERO (&handle_xfds);
266 /* Classify handles. Create fd sets for sockets, poll the others. */
267 for (i = 0; i < nfds; i++)
271 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
274 h = (HANDLE) _get_osfhandle (i);
281 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
282 WSAEnumNetworkEvents instead distinguishes the two correctly. */
283 ev.lNetworkEvents = 0xDEADBEEF;
284 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
285 if (ev.lNetworkEvents != 0xDEADBEEF)
287 int requested = FD_CLOSE;
289 /* See above; socket handles are mapped onto select, but we
290 need to map descriptors to handles. */
291 if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
293 requested |= FD_READ | FD_ACCEPT;
294 FD_SET ((SOCKET) h, rfds);
295 FD_SET ((SOCKET) h, &handle_rfds);
297 if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
299 requested |= FD_WRITE | FD_CONNECT;
300 FD_SET ((SOCKET) h, wfds);
301 FD_SET ((SOCKET) h, &handle_wfds);
303 if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
306 FD_SET ((SOCKET) h, xfds);
307 FD_SET ((SOCKET) h, &handle_xfds);
310 WSAEventSelect ((SOCKET) h, hEvent, requested);
315 handle_array[nhandles++] = h;
317 /* Poll now. If we get an event, do not wait below. */
318 if (wait_timeout != 0
319 && win32_poll_handle (h, i, &rbits, &wbits, &xbits))
324 if (wait_timeout == 0 || nsock == 0)
328 /* See if we need to wait in the loop below. If any select is ready,
329 do MsgWaitForMultipleObjects anyway to dispatch messages, but
330 no need to call select again. */
331 rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
334 /* Restore the fd_sets for the other select we do below. */
335 memcpy (&handle_rfds, rfds, sizeof (fd_set));
336 memcpy (&handle_wfds, wfds, sizeof (fd_set));
337 memcpy (&handle_xfds, xfds, sizeof (fd_set));
345 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
346 wait_timeout, QS_ALLINPUT);
348 if (ret == WAIT_OBJECT_0 + nhandles)
350 /* new input of some other kind */
352 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
354 TranslateMessage (&msg);
355 DispatchMessage (&msg);
362 /* If we haven't done it yet, check the status of the sockets. */
363 if (rc == 0 && nsock > 0)
364 rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
366 /* Now fill in the results. */
371 /* Place a sentinel at the end of the array. */
372 handle_array[nhandles] = NULL;
374 for (i = 0; i < nfds; i++)
376 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
379 h = (HANDLE) _get_osfhandle (i);
380 if (h != handle_array[nhandles])
382 /* Perform handle->descriptor mapping. Don't update rc, as these
383 results are counted in the return value of Winsock's select. */
384 WSAEventSelect ((SOCKET) h, NULL, 0);
385 if (FD_ISSET (h, &handle_rfds))
387 if (FD_ISSET (h, &handle_wfds))
389 if (FD_ISSET (h, &handle_xfds))
396 win32_poll_handle (h, i, &rbits, &wbits, &xbits);
397 if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
402 if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
407 if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
418 #endif /* Native Win32. */