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