Blame lib/select.c

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