Blame src/gl/select.c

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