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