poll: don't return uninitialized
[gnulib.git] / lib / poll.c
1 /* Emulation for poll(2)
2    Contributed by Paolo Bonzini.
3
4    Copyright 2001-2003, 2006-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
25 #include <sys/types.h>
26 #include "poll.h"
27 #include <errno.h>
28 #include <limits.h>
29 #include <assert.h>
30
31 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
32 #define WIN32_NATIVE
33 #include <winsock2.h>
34 #include <windows.h>
35 #include <io.h>
36 #include <stdio.h>
37 #include <conio.h>
38 #else
39 #include <sys/time.h>
40 #include <sys/socket.h>
41 #include <sys/select.h>
42 #include <unistd.h>
43 #endif
44
45 #ifdef HAVE_SYS_IOCTL_H
46 #include <sys/ioctl.h>
47 #endif
48 #ifdef HAVE_SYS_FILIO_H
49 #include <sys/filio.h>
50 #endif
51
52 #include <time.h>
53
54 #ifndef INFTIM
55 #define INFTIM (-1)
56 #endif
57
58 /* BeOS does not have MSG_PEEK.  */
59 #ifndef MSG_PEEK
60 #define MSG_PEEK 0
61 #endif
62
63 #ifdef WIN32_NATIVE
64
65 /* Declare data structures for ntdll functions.  */
66 typedef struct _FILE_PIPE_LOCAL_INFORMATION {
67   ULONG NamedPipeType;
68   ULONG NamedPipeConfiguration;
69   ULONG MaximumInstances;
70   ULONG CurrentInstances;
71   ULONG InboundQuota;
72   ULONG ReadDataAvailable;
73   ULONG OutboundQuota;
74   ULONG WriteQuotaAvailable;
75   ULONG NamedPipeState;
76   ULONG NamedPipeEnd;
77 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
78
79 typedef struct _IO_STATUS_BLOCK
80 {
81   union {
82     DWORD Status;
83     PVOID Pointer;
84   } u;
85   ULONG_PTR Information;
86 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
87
88 typedef enum _FILE_INFORMATION_CLASS {
89   FilePipeLocalInformation = 24
90 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
91
92 typedef DWORD (WINAPI *PNtQueryInformationFile)
93          (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
94
95 #ifndef PIPE_BUF
96 #define PIPE_BUF        512
97 #endif
98
99 /* Compute revents values for file handle H.  */
100
101 static int
102 win32_compute_revents (HANDLE h, int sought)
103 {
104   int i, ret, happened;
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   switch (GetFileType (h))
114     {
115     case FILE_TYPE_PIPE:
116       if (!once_only)
117         {
118           NtQueryInformationFile = (PNtQueryInformationFile)
119             GetProcAddress (GetModuleHandle ("ntdll.dll"),
120                             "NtQueryInformationFile");
121           once_only = TRUE;
122         }
123
124       happened = 0;
125       if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
126         {
127           if (avail)
128             happened |= sought & (POLLIN | POLLRDNORM);
129         }
130
131       else
132         {
133           /* It was the write-end of the pipe.  Check if it is writable.
134              If NtQueryInformationFile fails, optimistically assume the pipe is
135              writable.  This could happen on Win9x, where NtQueryInformationFile
136              is not available, or if we inherit a pipe that doesn't permit
137              FILE_READ_ATTRIBUTES access on the write end (I think this should
138              not happen since WinXP SP2; WINE seems fine too).  Otherwise,
139              ensure that enough space is available for atomic writes.  */
140           memset (&iosb, 0, sizeof (iosb));
141           memset (&fpli, 0, sizeof (fpli));
142
143           if (!NtQueryInformationFile
144               || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
145                                          FilePipeLocalInformation)
146               || fpli.WriteQuotaAvailable >= PIPE_BUF
147               || (fpli.OutboundQuota < PIPE_BUF &&
148                   fpli.WriteQuotaAvailable == fpli.OutboundQuota))
149             happened |= sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
150         }
151       return happened;
152
153     case FILE_TYPE_CHAR:
154       ret = WaitForSingleObject (h, 0);
155       if (ret == WAIT_OBJECT_0)
156         {
157           nbuffer = avail = 0;
158           bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
159           if (!bRet || nbuffer == 0)
160             return POLLHUP;
161
162           irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
163           bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
164           if (!bRet || avail == 0)
165             return POLLHUP;
166
167           for (i = 0; i < avail; i++)
168             if (irbuffer[i].EventType == KEY_EVENT)
169               return sought & ~(POLLPRI | POLLRDBAND);
170         }
171       break;
172
173     default:
174       ret = WaitForSingleObject (h, 0);
175       if (ret == WAIT_OBJECT_0)
176         return sought & ~(POLLPRI | POLLRDBAND);
177
178       break;
179     }
180
181   return sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
182 }
183
184 /* Convert fd_sets returned by select into revents values.  */
185
186 static int
187 win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
188 {
189   int happened = 0;
190
191   if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
192     happened |= (POLLIN | POLLRDNORM) & sought;
193
194   else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
195     {
196       int r, error;
197
198       char data[64];
199       WSASetLastError (0);
200       r = recv (h, data, sizeof (data), MSG_PEEK);
201       error = WSAGetLastError ();
202       WSASetLastError (0);
203
204       if (r > 0 || error == WSAENOTCONN)
205         happened |= (POLLIN | POLLRDNORM) & sought;
206
207       /* Distinguish hung-up sockets from other errors.  */
208       else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
209                || error == WSAECONNABORTED || error == WSAENETRESET)
210         happened |= POLLHUP;
211
212       else
213         happened |= POLLERR;
214     }
215
216   if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
217     happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
218
219   if (lNetworkEvents & FD_OOB)
220     happened |= (POLLPRI | POLLRDBAND) & sought;
221
222   return happened;
223 }
224
225 #else /* !MinGW */
226
227 /* Convert select(2) returned fd_sets into poll(2) revents values.  */
228 static int
229 compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
230 {
231   int happened = 0;
232   if (FD_ISSET (fd, rfds))
233     {
234       int r;
235       int socket_errno;
236
237 #if defined __MACH__ && defined __APPLE__
238       /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
239          for some kinds of descriptors.  Detect if this descriptor is a
240          connected socket, a server socket, or something else using a
241          0-byte recv, and use ioctl(2) to detect POLLHUP.  */
242       r = recv (fd, NULL, 0, MSG_PEEK);
243       socket_errno = (r < 0) ? errno : 0;
244       if (r == 0 || socket_errno == ENOTSOCK)
245         ioctl (fd, FIONREAD, &r);
246 #else
247       char data[64];
248       r = recv (fd, data, sizeof (data), MSG_PEEK);
249       socket_errno = (r < 0) ? errno : 0;
250 #endif
251       if (r == 0)
252         happened |= POLLHUP;
253
254       /* If the event happened on an unconnected server socket,
255          that's fine. */
256       else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
257         happened |= (POLLIN | POLLRDNORM) & sought;
258
259       /* Distinguish hung-up sockets from other errors.  */
260       else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
261                || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
262         happened |= POLLHUP;
263
264       else
265         happened |= POLLERR;
266     }
267
268   if (FD_ISSET (fd, wfds))
269     happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
270
271   if (FD_ISSET (fd, efds))
272     happened |= (POLLPRI | POLLRDBAND) & sought;
273
274   return happened;
275 }
276 #endif /* !MinGW */
277
278 int
279 poll (pfd, nfd, timeout)
280      struct pollfd *pfd;
281      nfds_t nfd;
282      int timeout;
283 {
284 #ifndef WIN32_NATIVE
285   fd_set rfds, wfds, efds;
286   struct timeval tv;
287   struct timeval *ptv;
288   int maxfd, rc;
289   nfds_t i;
290
291 #ifdef _SC_OPEN_MAX
292   static int sc_open_max = -1;
293
294   if (nfd < 0
295       || (nfd > sc_open_max
296           && (sc_open_max != -1
297               || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
298     {
299       errno = EINVAL;
300       return -1;
301     }
302 #else /* !_SC_OPEN_MAX */
303 #ifdef OPEN_MAX
304   if (nfd < 0 || nfd > OPEN_MAX)
305     {
306       errno = EINVAL;
307       return -1;
308     }
309 #endif /* OPEN_MAX -- else, no check is needed */
310 #endif /* !_SC_OPEN_MAX */
311
312   /* EFAULT is not necessary to implement, but let's do it in the
313      simplest case. */
314   if (!pfd)
315     {
316       errno = EFAULT;
317       return -1;
318     }
319
320   /* convert timeout number into a timeval structure */
321   if (timeout == 0)
322     {
323       ptv = &tv;
324       ptv->tv_sec = 0;
325       ptv->tv_usec = 0;
326     }
327   else if (timeout > 0)
328     {
329       ptv = &tv;
330       ptv->tv_sec = timeout / 1000;
331       ptv->tv_usec = (timeout % 1000) * 1000;
332     }
333   else if (timeout == INFTIM)
334     /* wait forever */
335     ptv = NULL;
336   else
337     {
338       errno = EINVAL;
339       return -1;
340     }
341
342   /* create fd sets and determine max fd */
343   maxfd = -1;
344   FD_ZERO (&rfds);
345   FD_ZERO (&wfds);
346   FD_ZERO (&efds);
347   for (i = 0; i < nfd; i++)
348     {
349       if (pfd[i].fd < 0)
350         continue;
351
352       if (pfd[i].events & (POLLIN | POLLRDNORM))
353         FD_SET (pfd[i].fd, &rfds);
354
355       /* see select(2): "the only exceptional condition detectable
356          is out-of-band data received on a socket", hence we push
357          POLLWRBAND events onto wfds instead of efds. */
358       if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
359         FD_SET (pfd[i].fd, &wfds);
360       if (pfd[i].events & (POLLPRI | POLLRDBAND))
361         FD_SET (pfd[i].fd, &efds);
362       if (pfd[i].fd >= maxfd
363           && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
364                                | POLLRDNORM | POLLRDBAND
365                                | POLLWRNORM | POLLWRBAND)))
366         {
367           maxfd = pfd[i].fd;
368           if (maxfd > FD_SETSIZE)
369             {
370               errno = EOVERFLOW;
371               return -1;
372             }
373         }
374     }
375
376   /* examine fd sets */
377   rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
378   if (rc < 0)
379     return rc;
380
381   /* establish results */
382   rc = 0;
383   for (i = 0; i < nfd; i++)
384     if (pfd[i].fd < 0)
385       pfd[i].revents = 0;
386     else
387       {
388         int happened = compute_revents (pfd[i].fd, pfd[i].events,
389                                         &rfds, &wfds, &efds);
390         if (happened)
391           {
392             pfd[i].revents = happened;
393             rc++;
394           }
395       }
396
397   return rc;
398 #else
399   static struct timeval tv0;
400   static HANDLE hEvent;
401   WSANETWORKEVENTS ev;
402   HANDLE h, handle_array[FD_SETSIZE + 2];
403   DWORD ret, wait_timeout, nhandles;
404   fd_set rfds, wfds, xfds;
405   BOOL poll_again;
406   MSG msg;
407   char sockbuf[256];
408   int rc = 0;
409   nfds_t i;
410
411   if (nfd < 0 || timeout < -1)
412     {
413       errno = EINVAL;
414       return -1;
415     }
416
417   if (!hEvent)
418     hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
419
420   handle_array[0] = hEvent;
421   nhandles = 1;
422   FD_ZERO (&rfds);
423   FD_ZERO (&wfds);
424   FD_ZERO (&xfds);
425
426   /* Classify socket handles and create fd sets. */
427   for (i = 0; i < nfd; i++)
428     {
429       size_t optlen = sizeof(sockbuf);
430       pfd[i].revents = 0;
431       if (pfd[i].fd < 0)
432         continue;
433       if (!(pfd[i].events & (POLLIN | POLLRDNORM |
434                              POLLOUT | POLLWRNORM | POLLWRBAND)))
435         continue;
436
437       h = (HANDLE) _get_osfhandle (pfd[i].fd);
438       assert (h != NULL);
439
440       /* Under Wine, it seems that getsockopt returns 0 for pipes too.
441          WSAEnumNetworkEvents instead distinguishes the two correctly.  */
442       ev.lNetworkEvents = 0xDEADBEEF;
443       WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
444       if (ev.lNetworkEvents != 0xDEADBEEF)
445         {
446           int requested = FD_CLOSE;
447
448           /* see above; socket handles are mapped onto select.  */
449           if (pfd[i].events & (POLLIN | POLLRDNORM))
450             {
451               requested |= FD_READ | FD_ACCEPT;
452               FD_SET ((SOCKET) h, &rfds);
453             }
454           if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
455             {
456               requested |= FD_WRITE | FD_CONNECT;
457               FD_SET ((SOCKET) h, &wfds);
458             }
459           if (pfd[i].events & (POLLPRI | POLLRDBAND))
460             {
461               requested |= FD_OOB;
462               FD_SET ((SOCKET) h, &xfds);
463             }
464
465           if (requested)
466             WSAEventSelect ((SOCKET) h, hEvent, requested);
467         }
468       else
469         {
470           handle_array[nhandles++] = h;
471
472           /* Poll now.  If we get an event, do not poll again.  */
473           pfd[i].revents = win32_compute_revents (h, pfd[i].events);
474           if (pfd[i].revents)
475             wait_timeout = 0;
476         }
477     }
478
479   if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
480     {
481       /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
482          no need to call select again.  */
483       poll_again = FALSE;
484       wait_timeout = 0;
485     }
486   else
487     {
488       poll_again = TRUE;
489       if (timeout == INFTIM)
490         wait_timeout = INFINITE;
491       else
492         wait_timeout = timeout;
493     }
494
495   for (;;)
496     {
497       ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
498                                        wait_timeout, QS_ALLINPUT);
499
500       if (ret == WAIT_OBJECT_0 + nhandles)
501         {
502           /* new input of some other kind */
503           BOOL bRet;
504           while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
505             {
506               TranslateMessage (&msg);
507               DispatchMessage (&msg);
508             }
509         }
510       else
511         break;
512     }
513
514   if (poll_again)
515     select (0, &rfds, &wfds, &xfds, &tv0);
516
517   /* Place a sentinel at the end of the array.  */
518   handle_array[nhandles] = NULL;
519   nhandles = 1;
520   for (i = 0; i < nfd; i++)
521     {
522       int happened;
523
524       if (pfd[i].fd < 0)
525         continue;
526       if (!(pfd[i].events & (POLLIN | POLLRDNORM |
527                              POLLOUT | POLLWRNORM | POLLWRBAND)))
528         continue;
529
530       h = (HANDLE) _get_osfhandle (pfd[i].fd);
531       if (h != handle_array[nhandles])
532         {
533           /* It's a socket.  */
534           WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
535           WSAEventSelect ((SOCKET) h, 0, 0);
536
537           /* If we're lucky, WSAEnumNetworkEvents already provided a way
538              to distinguish FD_READ and FD_ACCEPT; this saves a recv later.  */
539           if (FD_ISSET ((SOCKET) h, &rfds)
540               && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
541             ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
542           if (FD_ISSET ((SOCKET) h, &wfds))
543             ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
544           if (FD_ISSET ((SOCKET) h, &xfds))
545             ev.lNetworkEvents |= FD_OOB;
546
547           happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
548                                                    ev.lNetworkEvents);
549         }
550       else
551         {
552           /* Not a socket.  */
553           nhandles++;
554           happened = win32_compute_revents (h, pfd[i].events);
555         }
556
557        if ((pfd[i].revents |= happened) != 0)
558         rc++;
559     }
560
561   return rc;
562 #endif
563 }