more fixes.
[gnutls.git] / gl / select.c
blobe4fb44553b717dbfb435ce96b74dac2daed35f7f
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)
11 any later version.
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. */
22 #include <config.h>
23 #include <alloca.h>
24 #include <assert.h>
26 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
27 /* Native Win32. */
29 #include <sys/types.h>
30 #include <stdbool.h>
31 #include <errno.h>
32 #include <limits.h>
34 #include <winsock2.h>
35 #include <windows.h>
36 #include <io.h>
37 #include <stdio.h>
38 #include <conio.h>
39 #include <time.h>
41 struct bitset {
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 {
48 ULONG NamedPipeType;
49 ULONG NamedPipeConfiguration;
50 ULONG MaximumInstances;
51 ULONG CurrentInstances;
52 ULONG InboundQuota;
53 ULONG ReadDataAvailable;
54 ULONG OutboundQuota;
55 ULONG WriteQuotaAvailable;
56 ULONG NamedPipeState;
57 ULONG NamedPipeEnd;
58 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
60 typedef struct _IO_STATUS_BLOCK
62 union {
63 DWORD Status;
64 PVOID Pointer;
65 } u;
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);
76 #ifndef PIPE_BUF
77 #define PIPE_BUF 512
78 #endif
80 #define IsConsoleHandle(h) (((long) (h) & 3) == 3)
82 static BOOL
83 IsSocketHandle (HANDLE h)
85 WSANETWORKEVENTS ev;
87 if (IsConsoleHandle (h))
88 return FALSE;
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). */
99 static int
100 win32_poll_handle (HANDLE h, int fd, struct bitset *rbits, struct bitset *wbits,
101 struct bitset *xbits)
103 BOOL read, write, except;
104 int i, ret;
105 INPUT_RECORD *irbuffer;
106 DWORD avail, nbuffer;
107 BOOL bRet;
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))
116 case FILE_TYPE_DISK:
117 read = TRUE;
118 write = TRUE;
119 break;
121 case FILE_TYPE_PIPE:
122 if (!once_only)
124 NtQueryInformationFile = (PNtQueryInformationFile)
125 GetProcAddress (GetModuleHandle ("ntdll.dll"),
126 "NtQueryInformationFile");
127 once_only = TRUE;
130 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
132 if (avail)
133 read = TRUE;
135 else if (GetLastError () == ERROR_BROKEN_PIPE)
138 else
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))
156 write = TRUE;
158 break;
160 case FILE_TYPE_CHAR:
161 write = TRUE;
162 if (!(rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
163 break;
165 ret = WaitForSingleObject (h, 0);
166 if (ret == WAIT_OBJECT_0)
168 if (!IsConsoleHandle (h))
170 read = TRUE;
171 break;
174 nbuffer = avail = 0;
175 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
177 /* Screen buffers handles are filtered earlier. */
178 assert (bRet);
179 if (nbuffer == 0)
181 except = TRUE;
182 break;
185 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
186 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
187 if (!bRet || avail == 0)
189 except = TRUE;
190 break;
193 for (i = 0; i < avail; i++)
194 if (irbuffer[i].EventType == KEY_EVENT)
195 read = TRUE;
197 break;
199 default:
200 ret = WaitForSingleObject (h, 0);
201 write = TRUE;
202 if (ret == WAIT_OBJECT_0)
203 read = TRUE;
205 break;
208 ret = 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)));
212 ret++;
215 if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
217 wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
218 ret++;
221 if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
223 xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
224 ret++;
227 return ret;
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;
241 MSG msg;
242 int i, fd, rc;
244 if (nfds > FD_SETSIZE)
245 nfds = FD_SETSIZE;
247 if (!timeout)
248 wait_timeout = INFINITE;
249 else
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);
257 return 0;
261 if (!hEvent)
262 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
264 handle_array[0] = hEvent;
265 nhandles = 1;
266 nsock = 0;
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));
276 if (rfds)
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))
283 continue;
285 rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
286 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
288 else
289 rfds = (fd_set *) alloca (sizeof (fd_set));
291 if (wfds)
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))
298 continue;
300 wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
301 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
303 else
304 wfds = (fd_set *) alloca (sizeof (fd_set));
306 if (xfds)
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));
313 else
314 xfds = (fd_set *) alloca (sizeof (fd_set));
316 /* Zero all the fd_sets, including the application's. */
317 FD_ZERO (rfds);
318 FD_ZERO (wfds);
319 FD_ZERO (xfds);
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)
328 continue;
330 h = (HANDLE) _get_osfhandle (i);
331 if (!h)
333 errno = EBADF;
334 return -1;
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))))
357 requested |= FD_OOB;
358 FD_SET ((SOCKET) h, xfds);
359 FD_SET ((SOCKET) h, &handle_xfds);
362 WSAEventSelect ((SOCKET) h, hEvent, requested);
363 nsock++;
365 else
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))
372 wait_timeout = 0;
376 if (wait_timeout == 0 || nsock == 0)
377 rc = 0;
378 else
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);
384 if (rc == 0)
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));
391 else
392 wait_timeout = 0;
395 for (;;)
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 */
403 BOOL bRet;
404 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
406 TranslateMessage (&msg);
407 DispatchMessage (&msg);
410 else
411 break;
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. */
419 FD_ZERO (rfds);
420 FD_ZERO (wfds);
421 FD_ZERO (xfds);
423 /* Place a sentinel at the end of the array. */
424 handle_array[nhandles] = NULL;
425 nhandles = 1;
426 for (i = 0; i < nfds; i++)
428 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
429 continue;
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))
438 FD_SET (i, rfds);
439 if (FD_ISSET (h, &handle_wfds))
440 FD_SET (i, wfds);
441 if (FD_ISSET (h, &handle_xfds))
442 FD_SET (i, xfds);
444 else
446 /* Not a socket. */
447 nhandles++;
448 win32_poll_handle (h, i, &rbits, &wbits, &xbits);
449 if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
451 rc++;
452 FD_SET (i, rfds);
454 if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
456 rc++;
457 FD_SET (i, wfds);
459 if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
461 rc++;
462 FD_SET (i, xfds);
467 return rc;
470 #else /* ! Native Win32. */
472 #include <sys/select.h>
474 #undef select
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. */
481 if (nfds == 0)
483 nfds = 1;
484 rfds = NULL;
485 wfds = NULL;
486 xfds = NULL;
488 return select (nfds, rfds, wfds, xfds, timeout);
491 #endif