Blame gnulib-tests/select.c

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