Code

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