Do only one call to GetVersionEx in the common case.
[pspp] / lib / poll.c
index da0484482b54aad20b602df44e7480d7b9693482..3fa8872f76472a7837d2d7e3e968263f904e8c56 100644 (file)
@@ -1,7 +1,7 @@
 /* Emulation for poll(2)
    Contributed by Paolo Bonzini.
 
-   Copyright 2001, 2002, 2003, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright 2001-2003, 2006-2009 Free Software Foundation, Inc.
 
    This file is part of gnulib.
 
    with this program; if not, write to the Free Software Foundation,
    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
+/* Tell gcc not to warn about the (nfd < 0) tests, below.  */
+#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
+# pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
 #include <config.h>
 #include <alloca.h>
 
 #include <assert.h>
 
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-#define WIN32_NATIVE
-#include <winsock2.h>
-#include <windows.h>
-#include <io.h>
-#include <stdio.h>
-#include <conio.h>
+# define WIN32_NATIVE
+# include <winsock2.h>
+# include <windows.h>
+# include <io.h>
+# include <stdio.h>
+# include <conio.h>
 #else
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <unistd.h>
+# include <sys/time.h>
+# include <sys/socket.h>
+# include <sys/select.h>
+# include <unistd.h>
 #endif
 
 #ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
+# include <sys/ioctl.h>
 #endif
 #ifdef HAVE_SYS_FILIO_H
-#include <sys/filio.h>
+# include <sys/filio.h>
 #endif
 
 #include <time.h>
 
 #ifndef INFTIM
-#define INFTIM (-1)
+# define INFTIM (-1)
 #endif
 
 /* BeOS does not have MSG_PEEK.  */
 #ifndef MSG_PEEK
-#define MSG_PEEK 0
+# define MSG_PEEK 0
 #endif
 
 #ifdef WIN32_NATIVE
 
+#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
+
+static BOOL
+IsSocketHandle(HANDLE h)
+{
+  WSANETWORKEVENTS ev;
+
+  if (IsConsoleHandle (h))
+    return FALSE;
+
+  /* Under Wine, it seems that getsockopt returns 0 for pipes too.
+     WSAEnumNetworkEvents instead distinguishes the two correctly.  */
+  ev.lNetworkEvents = 0xDEADBEEF;
+  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+  return ev.lNetworkEvents != 0xDEADBEEF;
+}
+
 /* Declare data structures for ntdll functions.  */
 typedef struct _FILE_PIPE_LOCAL_INFORMATION {
   ULONG NamedPipeType;
@@ -92,14 +114,15 @@ typedef enum _FILE_INFORMATION_CLASS {
 typedef DWORD (WINAPI *PNtQueryInformationFile)
         (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
 
-#ifndef PIPE_BUF
-#define PIPE_BUF       512
-#endif
+# ifndef PIPE_BUF
+#  define PIPE_BUF     512
+# endif
 
-/* Compute revents values for file handle H.  */
+/* Compute revents values for file handle H.  If some events cannot happen
+   for the handle, eliminate them from *P_SOUGHT.  */
 
 static int
-win32_compute_revents (HANDLE h, int sought)
+win32_compute_revents (HANDLE h, int *p_sought)
 {
   int i, ret, happened;
   INPUT_RECORD *irbuffer;
@@ -125,7 +148,7 @@ win32_compute_revents (HANDLE h, int sought)
       if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
        {
          if (avail)
-           happened |= sought & (POLLIN | POLLRDNORM);
+           happened |= *p_sought & (POLLIN | POLLRDNORM);
        }
 
       else
@@ -146,18 +169,25 @@ win32_compute_revents (HANDLE h, int sought)
              || fpli.WriteQuotaAvailable >= PIPE_BUF
              || (fpli.OutboundQuota < PIPE_BUF &&
                  fpli.WriteQuotaAvailable == fpli.OutboundQuota))
-           happened |= sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+           happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
        }
       return happened;
 
     case FILE_TYPE_CHAR:
       ret = WaitForSingleObject (h, 0);
-      if (ret == WAIT_OBJECT_0)
-        {
-         nbuffer = avail = 0;
-         bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
-         if (!bRet || nbuffer == 0)
+      if (!IsConsoleHandle (h))
+       return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
+
+      nbuffer = avail = 0;
+      bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
+      if (bRet)
+       {
+         /* Input buffer.  */
+         *p_sought &= POLLIN | POLLRDNORM;
+         if (nbuffer == 0)
            return POLLHUP;
+         if (!*p_sought)
+           return 0;
 
          irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
          bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
@@ -166,19 +196,23 @@ win32_compute_revents (HANDLE h, int sought)
 
          for (i = 0; i < avail; i++)
            if (irbuffer[i].EventType == KEY_EVENT)
-             return sought & ~(POLLPRI | POLLRDBAND);
+             return *p_sought;
+         return 0;
+       }
+      else
+       {
+         /* Screen buffer.  */
+         *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
+         return *p_sought;
        }
-      break;
 
     default:
       ret = WaitForSingleObject (h, 0);
       if (ret == WAIT_OBJECT_0)
-        return sought & ~(POLLPRI | POLLRDBAND);
+        return *p_sought & ~(POLLPRI | POLLRDBAND);
 
-      break;
+      return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
     }
-
-  return sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
 }
 
 /* Convert fd_sets returned by select into revents values.  */
@@ -234,7 +268,7 @@ compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
       int r;
       int socket_errno;
 
-#if defined __MACH__ && defined __APPLE__
+# if defined __MACH__ && defined __APPLE__
       /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
          for some kinds of descriptors.  Detect if this descriptor is a
          connected socket, a server socket, or something else using a
@@ -243,11 +277,11 @@ compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
       socket_errno = (r < 0) ? errno : 0;
       if (r == 0 || socket_errno == ENOTSOCK)
        ioctl (fd, FIONREAD, &r);
-#else
+# else
       char data[64];
       r = recv (fd, data, sizeof (data), MSG_PEEK);
       socket_errno = (r < 0) ? errno : 0;
-#endif
+# endif
       if (r == 0)
        happened |= POLLHUP;
 
@@ -288,7 +322,7 @@ poll (pfd, nfd, timeout)
   int maxfd, rc;
   nfds_t i;
 
-#ifdef _SC_OPEN_MAX
+# ifdef _SC_OPEN_MAX
   static int sc_open_max = -1;
 
   if (nfd < 0
@@ -299,15 +333,15 @@ poll (pfd, nfd, timeout)
       errno = EINVAL;
       return -1;
     }
-#else /* !_SC_OPEN_MAX */
-#ifdef OPEN_MAX
+# else /* !_SC_OPEN_MAX */
+#  ifdef OPEN_MAX
   if (nfd < 0 || nfd > OPEN_MAX)
     {
       errno = EINVAL;
       return -1;
     }
-#endif /* OPEN_MAX -- else, no check is needed */
-#endif /* !_SC_OPEN_MAX */
+#  endif /* OPEN_MAX -- else, no check is needed */
+# endif /* !_SC_OPEN_MAX */
 
   /* EFAULT is not necessary to implement, but let's do it in the
      simplest case. */
@@ -404,8 +438,7 @@ poll (pfd, nfd, timeout)
   fd_set rfds, wfds, xfds;
   BOOL poll_again;
   MSG msg;
-  char sockbuf[256];
-  int rc;
+  int rc = 0;
   nfds_t i;
 
   if (nfd < 0 || timeout < -1)
@@ -426,37 +459,32 @@ poll (pfd, nfd, timeout)
   /* Classify socket handles and create fd sets. */
   for (i = 0; i < nfd; i++)
     {
-      size_t optlen = sizeof(sockbuf);
+      int sought = pfd[i].events;
       pfd[i].revents = 0;
       if (pfd[i].fd < 0)
         continue;
-      if (!(pfd[i].events & (POLLIN | POLLRDNORM |
-                             POLLOUT | POLLWRNORM | POLLWRBAND)))
+      if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
+                     | POLLPRI | POLLRDBAND)))
        continue;
 
       h = (HANDLE) _get_osfhandle (pfd[i].fd);
       assert (h != NULL);
-
-      /* Under Wine, it seems that getsockopt returns 0 for pipes too.
-        WSAEnumNetworkEvents instead distinguishes the two correctly.  */
-      ev.lNetworkEvents = 0xDEADBEEF;
-      WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
-      if (ev.lNetworkEvents != 0xDEADBEEF)
+      if (IsSocketHandle (h))
         {
           int requested = FD_CLOSE;
 
           /* see above; socket handles are mapped onto select.  */
-          if (pfd[i].events & (POLLIN | POLLRDNORM))
+          if (sought & (POLLIN | POLLRDNORM))
            {
               requested |= FD_READ | FD_ACCEPT;
              FD_SET ((SOCKET) h, &rfds);
            }
-          if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
+          if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
            {
               requested |= FD_WRITE | FD_CONNECT;
              FD_SET ((SOCKET) h, &wfds);
            }
-          if (pfd[i].events & (POLLPRI | POLLRDBAND))
+          if (sought & (POLLPRI | POLLRDBAND))
            {
               requested |= FD_OOB;
              FD_SET ((SOCKET) h, &xfds);
@@ -467,10 +495,13 @@ poll (pfd, nfd, timeout)
         }
       else
         {
-          handle_array[nhandles++] = h;
-
-         /* Poll now.  If we get an event, do not poll again.  */
-          pfd[i].revents = win32_compute_revents (h, pfd[i].events);
+         /* Poll now.  If we get an event, do not poll again.  Also,
+            screen buffer handles are waitable, and they'll block until
+            a character is available.  win32_compute_revents eliminates
+            bits for the "wrong" direction. */
+          pfd[i].revents = win32_compute_revents (h, &sought);
+         if (sought)
+           handle_array[nhandles++] = h;
           if (pfd[i].revents)
            wait_timeout = 0;
         }
@@ -550,8 +581,9 @@ poll (pfd, nfd, timeout)
       else
         {
           /* Not a socket.  */
+          int sought = pfd[i].events;
+          happened = win32_compute_revents (h, &sought);
           nhandles++;
-          happened = win32_compute_revents (h, pfd[i].events);
         }
 
        if ((pfd[i].revents |= happened) != 0)