Blame gnulib-tests/select.c

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