Blame src/gl/select.c

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