Blame lib/select.c

Packit 8f70b4
/* Emulation for select(2)
Packit 8f70b4
   Contributed by Paolo Bonzini.
Packit 8f70b4
Packit 8f70b4
   Copyright 2008-2018 Free Software Foundation, Inc.
Packit 8f70b4
Packit 8f70b4
   This file is part of gnulib.
Packit 8f70b4
Packit 8f70b4
   This program is free software; you can redistribute it and/or modify
Packit 8f70b4
   it under the terms of the GNU General Public License as published by
Packit 8f70b4
   the Free Software Foundation; either version 3, or (at your option)
Packit 8f70b4
   any later version.
Packit 8f70b4
Packit 8f70b4
   This program is distributed in the hope that it will be useful,
Packit 8f70b4
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8f70b4
   GNU General Public License for more details.
Packit 8f70b4
Packit 8f70b4
   You should have received a copy of the GNU General Public License along
Packit 8f70b4
   with this program; if not, see <https://www.gnu.org/licenses/>.  */
Packit 8f70b4
Packit 8f70b4
#include <config.h>
Packit 8f70b4
#include <alloca.h>
Packit 8f70b4
#include <assert.h>
Packit 8f70b4
Packit 8f70b4
#if defined _WIN32 && ! defined __CYGWIN__
Packit 8f70b4
/* Native Windows.  */
Packit 8f70b4
Packit 8f70b4
#include <sys/types.h>
Packit 8f70b4
#include <errno.h>
Packit 8f70b4
#include <limits.h>
Packit 8f70b4
Packit 8f70b4
#include <winsock2.h>
Packit 8f70b4
#include <windows.h>
Packit 8f70b4
#include <io.h>
Packit 8f70b4
#include <stdio.h>
Packit 8f70b4
#include <conio.h>
Packit 8f70b4
#include <time.h>
Packit 8f70b4
Packit 8f70b4
/* Get the overridden 'struct timeval'.  */
Packit 8f70b4
#include <sys/time.h>
Packit 8f70b4
Packit 8f70b4
#if GNULIB_MSVC_NOTHROW
Packit 8f70b4
# include "msvc-nothrow.h"
Packit 8f70b4
#else
Packit 8f70b4
# include <io.h>
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#undef select
Packit 8f70b4
Packit 8f70b4
struct bitset {
Packit 8f70b4
  unsigned char in[FD_SETSIZE / CHAR_BIT];
Packit 8f70b4
  unsigned char out[FD_SETSIZE / CHAR_BIT];
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
/* Declare data structures for ntdll functions.  */
Packit 8f70b4
typedef struct _FILE_PIPE_LOCAL_INFORMATION {
Packit 8f70b4
  ULONG NamedPipeType;
Packit 8f70b4
  ULONG NamedPipeConfiguration;
Packit 8f70b4
  ULONG MaximumInstances;
Packit 8f70b4
  ULONG CurrentInstances;
Packit 8f70b4
  ULONG InboundQuota;
Packit 8f70b4
  ULONG ReadDataAvailable;
Packit 8f70b4
  ULONG OutboundQuota;
Packit 8f70b4
  ULONG WriteQuotaAvailable;
Packit 8f70b4
  ULONG NamedPipeState;
Packit 8f70b4
  ULONG NamedPipeEnd;
Packit 8f70b4
} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
Packit 8f70b4
Packit 8f70b4
typedef struct _IO_STATUS_BLOCK
Packit 8f70b4
{
Packit 8f70b4
  union {
Packit 8f70b4
    DWORD Status;
Packit 8f70b4
    PVOID Pointer;
Packit 8f70b4
  } u;
Packit 8f70b4
  ULONG_PTR Information;
Packit 8f70b4
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
Packit 8f70b4
Packit 8f70b4
typedef enum _FILE_INFORMATION_CLASS {
Packit 8f70b4
  FilePipeLocalInformation = 24
Packit 8f70b4
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
Packit 8f70b4
Packit 8f70b4
typedef DWORD (WINAPI *PNtQueryInformationFile)
Packit 8f70b4
         (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
Packit 8f70b4
Packit 8f70b4
#ifndef PIPE_BUF
Packit 8f70b4
#define PIPE_BUF        512
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
static BOOL IsConsoleHandle (HANDLE h)
Packit 8f70b4
{
Packit 8f70b4
  DWORD mode;
Packit 8f70b4
  return GetConsoleMode (h, &mode) != 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
static BOOL
Packit 8f70b4
IsSocketHandle (HANDLE h)
Packit 8f70b4
{
Packit 8f70b4
  WSANETWORKEVENTS ev;
Packit 8f70b4
Packit 8f70b4
  if (IsConsoleHandle (h))
Packit 8f70b4
    return FALSE;
Packit 8f70b4
Packit 8f70b4
  /* Under Wine, it seems that getsockopt returns 0 for pipes too.
Packit 8f70b4
     WSAEnumNetworkEvents instead distinguishes the two correctly.  */
Packit 8f70b4
  ev.lNetworkEvents = 0xDEADBEEF;
Packit 8f70b4
  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev;;
Packit 8f70b4
  return ev.lNetworkEvents != 0xDEADBEEF;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
/* Compute output fd_sets for libc descriptor FD (whose Windows handle is
Packit 8f70b4
   H).  */
Packit 8f70b4
Packit 8f70b4
static int
Packit 8f70b4
windows_poll_handle (HANDLE h, int fd,
Packit 8f70b4
                     struct bitset *rbits,
Packit 8f70b4
                     struct bitset *wbits,
Packit 8f70b4
                     struct bitset *xbits)
Packit 8f70b4
{
Packit 8f70b4
  BOOL read, write, except;
Packit 8f70b4
  int i, ret;
Packit 8f70b4
  INPUT_RECORD *irbuffer;
Packit 8f70b4
  DWORD avail, nbuffer;
Packit 8f70b4
  BOOL bRet;
Packit 8f70b4
  IO_STATUS_BLOCK iosb;
Packit 8f70b4
  FILE_PIPE_LOCAL_INFORMATION fpli;
Packit 8f70b4
  static PNtQueryInformationFile NtQueryInformationFile;
Packit 8f70b4
  static BOOL once_only;
Packit 8f70b4
Packit 8f70b4
  read = write = except = FALSE;
Packit 8f70b4
  switch (GetFileType (h))
Packit 8f70b4
    {
Packit 8f70b4
    case FILE_TYPE_DISK:
Packit 8f70b4
      read = TRUE;
Packit 8f70b4
      write = TRUE;
Packit 8f70b4
      break;
Packit 8f70b4
Packit 8f70b4
    case FILE_TYPE_PIPE:
Packit 8f70b4
      if (!once_only)
Packit 8f70b4
        {
Packit 8f70b4
          NtQueryInformationFile = (PNtQueryInformationFile)
Packit 8f70b4
            GetProcAddress (GetModuleHandle ("ntdll.dll"),
Packit 8f70b4
                            "NtQueryInformationFile");
Packit 8f70b4
          once_only = TRUE;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
Packit 8f70b4
        {
Packit 8f70b4
          if (avail)
Packit 8f70b4
            read = TRUE;
Packit 8f70b4
        }
Packit 8f70b4
      else if (GetLastError () == ERROR_BROKEN_PIPE)
Packit 8f70b4
        ;
Packit 8f70b4
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          /* It was the write-end of the pipe.  Check if it is writable.
Packit 8f70b4
             If NtQueryInformationFile fails, optimistically assume the pipe is
Packit 8f70b4
             writable.  This could happen on Windows 9x, where
Packit 8f70b4
             NtQueryInformationFile is not available, or if we inherit a pipe
Packit 8f70b4
             that doesn't permit FILE_READ_ATTRIBUTES access on the write end
Packit 8f70b4
             (I think this should not happen since Windows XP SP2; WINE seems
Packit 8f70b4
             fine too).  Otherwise, ensure that enough space is available for
Packit 8f70b4
             atomic writes.  */
Packit 8f70b4
          memset (&iosb, 0, sizeof (iosb));
Packit 8f70b4
          memset (&fpli, 0, sizeof (fpli));
Packit 8f70b4
Packit 8f70b4
          if (!NtQueryInformationFile
Packit 8f70b4
              || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
Packit 8f70b4
                                         FilePipeLocalInformation)
Packit 8f70b4
              || fpli.WriteQuotaAvailable >= PIPE_BUF
Packit 8f70b4
              || (fpli.OutboundQuota < PIPE_BUF &&
Packit 8f70b4
                  fpli.WriteQuotaAvailable == fpli.OutboundQuota))
Packit 8f70b4
            write = TRUE;
Packit 8f70b4
        }
Packit 8f70b4
      break;
Packit 8f70b4
Packit 8f70b4
    case FILE_TYPE_CHAR:
Packit 8f70b4
      write = TRUE;
Packit 8f70b4
      if (!(rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
Packit 8f70b4
        break;
Packit 8f70b4
Packit 8f70b4
      ret = WaitForSingleObject (h, 0);
Packit 8f70b4
      if (ret == WAIT_OBJECT_0)
Packit 8f70b4
        {
Packit 8f70b4
          if (!IsConsoleHandle (h))
Packit 8f70b4
            {
Packit 8f70b4
              read = TRUE;
Packit 8f70b4
              break;
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          nbuffer = avail = 0;
Packit 8f70b4
          bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
Packit 8f70b4
Packit 8f70b4
          /* Screen buffers handles are filtered earlier.  */
Packit 8f70b4
          assert (bRet);
Packit 8f70b4
          if (nbuffer == 0)
Packit 8f70b4
            {
Packit 8f70b4
              except = TRUE;
Packit 8f70b4
              break;
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
Packit 8f70b4
          bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
Packit 8f70b4
          if (!bRet || avail == 0)
Packit 8f70b4
            {
Packit 8f70b4
              except = TRUE;
Packit 8f70b4
              break;
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          for (i = 0; i < avail; i++)
Packit 8f70b4
            if (irbuffer[i].EventType == KEY_EVENT)
Packit 8f70b4
              read = TRUE;
Packit 8f70b4
        }
Packit 8f70b4
      break;
Packit 8f70b4
Packit 8f70b4
    default:
Packit 8f70b4
      ret = WaitForSingleObject (h, 0);
Packit 8f70b4
      write = TRUE;
Packit 8f70b4
      if (ret == WAIT_OBJECT_0)
Packit 8f70b4
        read = TRUE;
Packit 8f70b4
Packit 8f70b4
      break;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  ret = 0;
Packit 8f70b4
  if (read && (rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
Packit 8f70b4
    {
Packit 8f70b4
      rbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
Packit 8f70b4
      ret++;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
Packit 8f70b4
    {
Packit 8f70b4
      wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
Packit 8f70b4
      ret++;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
Packit 8f70b4
    {
Packit 8f70b4
      xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
Packit 8f70b4
      ret++;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  return ret;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int
Packit 8f70b4
rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
Packit 8f70b4
            struct timeval *timeout)
Packit 8f70b4
#undef timeval
Packit 8f70b4
{
Packit 8f70b4
  static struct timeval tv0;
Packit 8f70b4
  static HANDLE hEvent;
Packit 8f70b4
  HANDLE h, handle_array[FD_SETSIZE + 2];
Packit 8f70b4
  fd_set handle_rfds, handle_wfds, handle_xfds;
Packit 8f70b4
  struct bitset rbits, wbits, xbits;
Packit 8f70b4
  unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
Packit 8f70b4
  DWORD ret, wait_timeout, nhandles, nsock, nbuffer;
Packit 8f70b4
  MSG msg;
Packit 8f70b4
  int i, fd, rc;
Packit 8f70b4
  clock_t tend;
Packit 8f70b4
Packit 8f70b4
  if (nfds > FD_SETSIZE)
Packit 8f70b4
    nfds = FD_SETSIZE;
Packit 8f70b4
Packit 8f70b4
  if (!timeout)
Packit 8f70b4
    wait_timeout = INFINITE;
Packit 8f70b4
  else
Packit 8f70b4
    {
Packit 8f70b4
      wait_timeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
Packit 8f70b4
Packit 8f70b4
      /* select is also used as a portable usleep.  */
Packit 8f70b4
      if (!rfds && !wfds && !xfds)
Packit 8f70b4
        {
Packit 8f70b4
          Sleep (wait_timeout);
Packit 8f70b4
          return 0;
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  if (!hEvent)
Packit 8f70b4
    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
Packit 8f70b4
Packit 8f70b4
  handle_array[0] = hEvent;
Packit 8f70b4
  nhandles = 1;
Packit 8f70b4
  nsock = 0;
Packit 8f70b4
Packit 8f70b4
  /* Copy descriptors to bitsets.  At the same time, eliminate
Packit 8f70b4
     bits in the "wrong" direction for console input buffers
Packit 8f70b4
     and screen buffers, because screen buffers are waitable
Packit 8f70b4
     and they will block until a character is available.  */
Packit 8f70b4
  memset (&rbits, 0, sizeof (rbits));
Packit 8f70b4
  memset (&wbits, 0, sizeof (wbits));
Packit 8f70b4
  memset (&xbits, 0, sizeof (xbits));
Packit 8f70b4
  memset (anyfds_in, 0, sizeof (anyfds_in));
Packit 8f70b4
  if (rfds)
Packit 8f70b4
    for (i = 0; i < rfds->fd_count; i++)
Packit 8f70b4
      {
Packit 8f70b4
        fd = rfds->fd_array[i];
Packit 8f70b4
        h = (HANDLE) _get_osfhandle (fd);
Packit 8f70b4
        if (IsConsoleHandle (h)
Packit 8f70b4
            && !GetNumberOfConsoleInputEvents (h, &nbuffer))
Packit 8f70b4
          continue;
Packit 8f70b4
Packit 8f70b4
        rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
Packit 8f70b4
        anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
Packit 8f70b4
      }
Packit 8f70b4
  else
Packit 8f70b4
    rfds = (fd_set *) alloca (sizeof (fd_set));
Packit 8f70b4
Packit 8f70b4
  if (wfds)
Packit 8f70b4
    for (i = 0; i < wfds->fd_count; i++)
Packit 8f70b4
      {
Packit 8f70b4
        fd = wfds->fd_array[i];
Packit 8f70b4
        h = (HANDLE) _get_osfhandle (fd);
Packit 8f70b4
        if (IsConsoleHandle (h)
Packit 8f70b4
            && GetNumberOfConsoleInputEvents (h, &nbuffer))
Packit 8f70b4
          continue;
Packit 8f70b4
Packit 8f70b4
        wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
Packit 8f70b4
        anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
Packit 8f70b4
      }
Packit 8f70b4
  else
Packit 8f70b4
    wfds = (fd_set *) alloca (sizeof (fd_set));
Packit 8f70b4
Packit 8f70b4
  if (xfds)
Packit 8f70b4
    for (i = 0; i < xfds->fd_count; i++)
Packit 8f70b4
      {
Packit 8f70b4
        fd = xfds->fd_array[i];
Packit 8f70b4
        xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
Packit 8f70b4
        anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
Packit 8f70b4
      }
Packit 8f70b4
  else
Packit 8f70b4
    xfds = (fd_set *) alloca (sizeof (fd_set));
Packit 8f70b4
Packit 8f70b4
  /* Zero all the fd_sets, including the application's.  */
Packit 8f70b4
  FD_ZERO (rfds);
Packit 8f70b4
  FD_ZERO (wfds);
Packit 8f70b4
  FD_ZERO (xfds);
Packit 8f70b4
  FD_ZERO (&handle_rfds);
Packit 8f70b4
  FD_ZERO (&handle_wfds);
Packit 8f70b4
  FD_ZERO (&handle_xfds);
Packit 8f70b4
Packit 8f70b4
  /* Classify handles.  Create fd sets for sockets, poll the others. */
Packit 8f70b4
  for (i = 0; i < nfds; i++)
Packit 8f70b4
    {
Packit 8f70b4
      if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
Packit 8f70b4
        continue;
Packit 8f70b4
Packit 8f70b4
      h = (HANDLE) _get_osfhandle (i);
Packit 8f70b4
      if (!h)
Packit 8f70b4
        {
Packit 8f70b4
          errno = EBADF;
Packit 8f70b4
          return -1;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      if (IsSocketHandle (h))
Packit 8f70b4
        {
Packit 8f70b4
          int requested = FD_CLOSE;
Packit 8f70b4
Packit 8f70b4
          /* See above; socket handles are mapped onto select, but we
Packit 8f70b4
             need to map descriptors to handles.  */
Packit 8f70b4
          if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
Packit 8f70b4
            {
Packit 8f70b4
              requested |= FD_READ | FD_ACCEPT;
Packit 8f70b4
              FD_SET ((SOCKET) h, rfds);
Packit 8f70b4
              FD_SET ((SOCKET) h, &handle_rfds);
Packit 8f70b4
            }
Packit 8f70b4
          if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
Packit 8f70b4
            {
Packit 8f70b4
              requested |= FD_WRITE | FD_CONNECT;
Packit 8f70b4
              FD_SET ((SOCKET) h, wfds);
Packit 8f70b4
              FD_SET ((SOCKET) h, &handle_wfds);
Packit 8f70b4
            }
Packit 8f70b4
          if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
Packit 8f70b4
            {
Packit 8f70b4
              requested |= FD_OOB;
Packit 8f70b4
              FD_SET ((SOCKET) h, xfds);
Packit 8f70b4
              FD_SET ((SOCKET) h, &handle_xfds);
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          WSAEventSelect ((SOCKET) h, hEvent, requested);
Packit 8f70b4
          nsock++;
Packit 8f70b4
        }
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          handle_array[nhandles++] = h;
Packit 8f70b4
Packit 8f70b4
          /* Poll now.  If we get an event, do not wait below.  */
Packit 8f70b4
          if (wait_timeout != 0
Packit 8f70b4
              && windows_poll_handle (h, i, &rbits, &wbits, &xbits))
Packit 8f70b4
            wait_timeout = 0;
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  /* Place a sentinel at the end of the array.  */
Packit 8f70b4
  handle_array[nhandles] = NULL;
Packit 8f70b4
Packit 8f70b4
  /* When will the waiting period expire?  */
Packit 8f70b4
  if (wait_timeout != INFINITE)
Packit 8f70b4
    tend = clock () + wait_timeout;
Packit 8f70b4
Packit 8f70b4
restart:
Packit 8f70b4
  if (wait_timeout == 0 || nsock == 0)
Packit 8f70b4
    rc = 0;
Packit 8f70b4
  else
Packit 8f70b4
    {
Packit 8f70b4
      /* See if we need to wait in the loop below.  If any select is ready,
Packit 8f70b4
         do MsgWaitForMultipleObjects anyway to dispatch messages, but
Packit 8f70b4
         no need to call select again.  */
Packit 8f70b4
      rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
Packit 8f70b4
      if (rc == 0)
Packit 8f70b4
        {
Packit 8f70b4
          /* Restore the fd_sets for the other select we do below.  */
Packit 8f70b4
          memcpy (&handle_rfds, rfds, sizeof (fd_set));
Packit 8f70b4
          memcpy (&handle_wfds, wfds, sizeof (fd_set));
Packit 8f70b4
          memcpy (&handle_xfds, xfds, sizeof (fd_set));
Packit 8f70b4
        }
Packit 8f70b4
      else
Packit 8f70b4
        wait_timeout = 0;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  /* How much is left to wait?  */
Packit 8f70b4
  if (wait_timeout != INFINITE)
Packit 8f70b4
    {
Packit 8f70b4
      clock_t tnow = clock ();
Packit 8f70b4
      if (tend >= tnow)
Packit 8f70b4
        wait_timeout = tend - tnow;
Packit 8f70b4
      else
Packit 8f70b4
        wait_timeout = 0;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  for (;;)
Packit 8f70b4
    {
Packit 8f70b4
      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
Packit 8f70b4
                                       wait_timeout, QS_ALLINPUT);
Packit 8f70b4
Packit 8f70b4
      if (ret == WAIT_OBJECT_0 + nhandles)
Packit 8f70b4
        {
Packit 8f70b4
          /* new input of some other kind */
Packit 8f70b4
          BOOL bRet;
Packit 8f70b4
          while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
Packit 8f70b4
            {
Packit 8f70b4
              TranslateMessage (&msg;;
Packit 8f70b4
              DispatchMessage (&msg;;
Packit 8f70b4
            }
Packit 8f70b4
        }
Packit 8f70b4
      else
Packit 8f70b4
        break;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  /* If we haven't done it yet, check the status of the sockets.  */
Packit 8f70b4
  if (rc == 0 && nsock > 0)
Packit 8f70b4
    rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
Packit 8f70b4
Packit 8f70b4
  if (nhandles > 1)
Packit 8f70b4
    {
Packit 8f70b4
      /* Count results that are not counted in the return value of select.  */
Packit 8f70b4
      nhandles = 1;
Packit 8f70b4
      for (i = 0; i < nfds; i++)
Packit 8f70b4
        {
Packit 8f70b4
          if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
Packit 8f70b4
            continue;
Packit 8f70b4
Packit 8f70b4
          h = (HANDLE) _get_osfhandle (i);
Packit 8f70b4
          if (h == handle_array[nhandles])
Packit 8f70b4
            {
Packit 8f70b4
              /* Not a socket.  */
Packit 8f70b4
              nhandles++;
Packit 8f70b4
              windows_poll_handle (h, i, &rbits, &wbits, &xbits);
Packit 8f70b4
              if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
Packit 8f70b4
                  || wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
Packit 8f70b4
                  || xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
Packit 8f70b4
                rc++;
Packit 8f70b4
            }
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      if (rc == 0
Packit 8f70b4
          && (wait_timeout == INFINITE
Packit 8f70b4
              /* If NHANDLES > 1, but no bits are set, it means we've
Packit 8f70b4
                 been told incorrectly that some handle was signaled.
Packit 8f70b4
                 This happens with anonymous pipes, which always cause
Packit 8f70b4
                 MsgWaitForMultipleObjects to exit immediately, but no
Packit 8f70b4
                 data is found ready to be read by windows_poll_handle.
Packit 8f70b4
                 To avoid a total failure (whereby we return zero and
Packit 8f70b4
                 don't wait at all), let's poll in a more busy loop.  */
Packit 8f70b4
              || (wait_timeout != 0 && nhandles > 1)))
Packit 8f70b4
        {
Packit 8f70b4
          /* Sleep 1 millisecond to avoid busy wait and retry with the
Packit 8f70b4
             original fd_sets.  */
Packit 8f70b4
          memcpy (&handle_rfds, rfds, sizeof (fd_set));
Packit 8f70b4
          memcpy (&handle_wfds, wfds, sizeof (fd_set));
Packit 8f70b4
          memcpy (&handle_xfds, xfds, sizeof (fd_set));
Packit 8f70b4
          SleepEx (1, TRUE);
Packit 8f70b4
          goto restart;
Packit 8f70b4
        }
Packit 8f70b4
      if (timeout && wait_timeout == 0 && rc == 0)
Packit 8f70b4
        timeout->tv_sec = timeout->tv_usec = 0;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  /* Now fill in the results.  */
Packit 8f70b4
  FD_ZERO (rfds);
Packit 8f70b4
  FD_ZERO (wfds);
Packit 8f70b4
  FD_ZERO (xfds);
Packit 8f70b4
  nhandles = 1;
Packit 8f70b4
  for (i = 0; i < nfds; i++)
Packit 8f70b4
    {
Packit 8f70b4
      if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
Packit 8f70b4
        continue;
Packit 8f70b4
Packit 8f70b4
      h = (HANDLE) _get_osfhandle (i);
Packit 8f70b4
      if (h != handle_array[nhandles])
Packit 8f70b4
        {
Packit 8f70b4
          /* Perform handle->descriptor mapping.  */
Packit 8f70b4
          WSAEventSelect ((SOCKET) h, NULL, 0);
Packit 8f70b4
          if (FD_ISSET (h, &handle_rfds))
Packit 8f70b4
            FD_SET (i, rfds);
Packit 8f70b4
          if (FD_ISSET (h, &handle_wfds))
Packit 8f70b4
            FD_SET (i, wfds);
Packit 8f70b4
          if (FD_ISSET (h, &handle_xfds))
Packit 8f70b4
            FD_SET (i, xfds);
Packit 8f70b4
        }
Packit 8f70b4
      else
Packit 8f70b4
        {
Packit 8f70b4
          /* Not a socket.  */
Packit 8f70b4
          nhandles++;
Packit 8f70b4
          if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
Packit 8f70b4
            FD_SET (i, rfds);
Packit 8f70b4
          if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
Packit 8f70b4
            FD_SET (i, wfds);
Packit 8f70b4
          if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
Packit 8f70b4
            FD_SET (i, xfds);
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  return rc;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#else /* ! Native Windows.  */
Packit 8f70b4
Packit 8f70b4
#include <sys/select.h>
Packit 8f70b4
#include <stddef.h> /* NULL */
Packit 8f70b4
#include <errno.h>
Packit 8f70b4
#include <unistd.h>
Packit 8f70b4
Packit 8f70b4
#undef select
Packit 8f70b4
Packit 8f70b4
int
Packit 8f70b4
rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
Packit 8f70b4
            struct timeval *timeout)
Packit 8f70b4
{
Packit 8f70b4
  int i;
Packit 8f70b4
Packit 8f70b4
  /* FreeBSD 8.2 has a bug: it does not always detect invalid fds.  */
Packit 8f70b4
  if (nfds < 0 || nfds > FD_SETSIZE)
Packit 8f70b4
    {
Packit 8f70b4
      errno = EINVAL;
Packit 8f70b4
      return -1;
Packit 8f70b4
    }
Packit 8f70b4
  for (i = 0; i < nfds; i++)
Packit 8f70b4
    {
Packit 8f70b4
      if (((rfds && FD_ISSET (i, rfds))
Packit 8f70b4
           || (wfds && FD_ISSET (i, wfds))
Packit 8f70b4
           || (xfds && FD_ISSET (i, xfds)))
Packit 8f70b4
          && dup2 (i, i) != i)
Packit 8f70b4
        return -1;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  /* Interix 3.5 has a bug: it does not support nfds == 0.  */
Packit 8f70b4
  if (nfds == 0)
Packit 8f70b4
    {
Packit 8f70b4
      nfds = 1;
Packit 8f70b4
      rfds = NULL;
Packit 8f70b4
      wfds = NULL;
Packit 8f70b4
      xfds = NULL;
Packit 8f70b4
    }
Packit 8f70b4
  return select (nfds, rfds, wfds, xfds, timeout);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#endif