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