1/* Emulation for poll(2)
   2   Contributed by Paolo Bonzini.
   3   Copyright 2001-2003, 2006-2010 Free Software Foundation, Inc.
   5   This file is part of gnulib.
   7   This program is free software; you can redistribute it and/or modify
   9   it under the terms of the GNU General Public License as published by
  10   the Free Software Foundation; either version 2, or (at your option)
  11   any later version.
  12   This program is distributed in the hope that it will be useful,
  14   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16   GNU General Public License for more details.
  17   You should have received a copy of the GNU General Public License along
  19   with this program; if not, write to the Free Software Foundation,
  20   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
  21/* Tell gcc not to warn about the (nfd < 0) tests, below.  */
  23#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
  24# pragma GCC diagnostic ignored "-Wtype-limits"
  25#endif
  26#include <malloc.h>
  28#include <sys/types.h>
  30#include "poll.h"
  31#include <errno.h>
  32#include <limits.h>
  33#include <assert.h>
  34#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
  36# define WIN32_NATIVE
  37# include <winsock2.h>
  38# include <windows.h>
  39# include <io.h>
  40# include <stdio.h>
  41# include <conio.h>
  42#else
  43# include <sys/time.h>
  44# include <sys/socket.h>
  45# include <sys/select.h>
  46# include <unistd.h>
  47#endif
  48#ifdef HAVE_SYS_IOCTL_H
  50# include <sys/ioctl.h>
  51#endif
  52#ifdef HAVE_SYS_FILIO_H
  53# include <sys/filio.h>
  54#endif
  55#include <time.h>
  57#ifndef INFTIM
  59# define INFTIM (-1)
  60#endif
  61/* BeOS does not have MSG_PEEK.  */
  63#ifndef MSG_PEEK
  64# define MSG_PEEK 0
  65#endif
  66#ifdef WIN32_NATIVE
  68#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
  70static BOOL
  72IsSocketHandle (HANDLE h)
  73{
  74  WSANETWORKEVENTS ev;
  75  if (IsConsoleHandle (h))
  77    return FALSE;
  78  /* Under Wine, it seems that getsockopt returns 0 for pipes too.
  80     WSAEnumNetworkEvents instead distinguishes the two correctly.  */
  81  ev.lNetworkEvents = 0xDEADBEEF;
  82  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
  83  return ev.lNetworkEvents != 0xDEADBEEF;
  84}
  85/* Declare data structures for ntdll functions.  */
  87typedef struct _FILE_PIPE_LOCAL_INFORMATION {
  88  ULONG NamedPipeType;
  89  ULONG NamedPipeConfiguration;
  90  ULONG MaximumInstances;
  91  ULONG CurrentInstances;
  92  ULONG InboundQuota;
  93  ULONG ReadDataAvailable;
  94  ULONG OutboundQuota;
  95  ULONG WriteQuotaAvailable;
  96  ULONG NamedPipeState;
  97  ULONG NamedPipeEnd;
  98} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
  99typedef struct _IO_STATUS_BLOCK
 101{
 102  union {
 103    DWORD Status;
 104    PVOID Pointer;
 105  } u;
 106  ULONG_PTR Information;
 107} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
 108typedef enum _FILE_INFORMATION_CLASS {
 110  FilePipeLocalInformation = 24
 111} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
 112typedef DWORD (WINAPI *PNtQueryInformationFile)
 114         (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
 115# ifndef PIPE_BUF
 117#  define PIPE_BUF      512
 118# endif
 119/* Compute revents values for file handle H.  If some events cannot happen
 121   for the handle, eliminate them from *P_SOUGHT.  */
 122static int
 124win32_compute_revents (HANDLE h, int *p_sought)
 125{
 126  int i, ret, happened;
 127  INPUT_RECORD *irbuffer;
 128  DWORD avail, nbuffer;
 129  BOOL bRet;
 130  IO_STATUS_BLOCK iosb;
 131  FILE_PIPE_LOCAL_INFORMATION fpli;
 132  static PNtQueryInformationFile NtQueryInformationFile;
 133  static BOOL once_only;
 134  switch (GetFileType (h))
 136    {
 137    case FILE_TYPE_PIPE:
 138      if (!once_only)
 139        {
 140          NtQueryInformationFile = (PNtQueryInformationFile)
 141            GetProcAddress (GetModuleHandle ("ntdll.dll"),
 142                            "NtQueryInformationFile");
 143          once_only = TRUE;
 144        }
 145      happened = 0;
 147      if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
 148        {
 149          if (avail)
 150            happened |= *p_sought & (POLLIN | POLLRDNORM);
 151        }
 152      else if (GetLastError () == ERROR_BROKEN_PIPE)
 153        happened |= POLLHUP;
 154      else
 156        {
 157          /* It was the write-end of the pipe.  Check if it is writable.
 158             If NtQueryInformationFile fails, optimistically assume the pipe is
 159             writable.  This could happen on Win9x, where NtQueryInformationFile
 160             is not available, or if we inherit a pipe that doesn't permit
 161             FILE_READ_ATTRIBUTES access on the write end (I think this should
 162             not happen since WinXP SP2; WINE seems fine too).  Otherwise,
 163             ensure that enough space is available for atomic writes.  */
 164          memset (&iosb, 0, sizeof (iosb));
 165          memset (&fpli, 0, sizeof (fpli));
 166          if (!NtQueryInformationFile
 168              || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
 169                                         FilePipeLocalInformation)
 170              || fpli.WriteQuotaAvailable >= PIPE_BUF
 171              || (fpli.OutboundQuota < PIPE_BUF &&
 172                  fpli.WriteQuotaAvailable == fpli.OutboundQuota))
 173            happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
 174        }
 175      return happened;
 176    case FILE_TYPE_CHAR:
 178      ret = WaitForSingleObject (h, 0);
 179      if (!IsConsoleHandle (h))
 180        return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
 181      nbuffer = avail = 0;
 183      bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
 184      if (bRet)
 185        {
 186          /* Input buffer.  */
 187          *p_sought &= POLLIN | POLLRDNORM;
 188          if (nbuffer == 0)
 189            return POLLHUP;
 190          if (!*p_sought)
 191            return 0;
 192          irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
 194          bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
 195          if (!bRet || avail == 0)
 196            return POLLHUP;
 197          for (i = 0; i < avail; i++)
 199            if (irbuffer[i].EventType == KEY_EVENT)
 200              return *p_sought;
 201          return 0;
 202        }
 203      else
 204        {
 205          /* Screen buffer.  */
 206          *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
 207          return *p_sought;
 208        }
 209    default:
 211      ret = WaitForSingleObject (h, 0);
 212      if (ret == WAIT_OBJECT_0)
 213        return *p_sought & ~(POLLPRI | POLLRDBAND);
 214      return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
 216    }
 217}
 218/* Convert fd_sets returned by select into revents values.  */
 220static int
 222win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
 223{
 224  int happened = 0;
 225  if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
 227    happened |= (POLLIN | POLLRDNORM) & sought;
 228  else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
 230    {
 231      int r, error;
 232      char data[64];
 234      WSASetLastError (0);
 235      r = recv (h, data, sizeof (data), MSG_PEEK);
 236      error = WSAGetLastError ();
 237      WSASetLastError (0);
 238      if (r > 0 || error == WSAENOTCONN)
 240        happened |= (POLLIN | POLLRDNORM) & sought;
 241      /* Distinguish hung-up sockets from other errors.  */
 243      else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
 244               || error == WSAECONNABORTED || error == WSAENETRESET)
 245        happened |= POLLHUP;
 246      else
 248        happened |= POLLERR;
 249    }
 250  if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
 252    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
 253  if (lNetworkEvents & FD_OOB)
 255    happened |= (POLLPRI | POLLRDBAND) & sought;
 256  return happened;
 258}
 259#else /* !MinGW */
 261/* Convert select(2) returned fd_sets into poll(2) revents values.  */
 263static int
 264compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
 265{
 266  int happened = 0;
 267  if (FD_ISSET (fd, rfds))
 268    {
 269      int r;
 270      int socket_errno;
 271# if defined __MACH__ && defined __APPLE__
 273      /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
 274         for some kinds of descriptors.  Detect if this descriptor is a
 275         connected socket, a server socket, or something else using a
 276         0-byte recv, and use ioctl(2) to detect POLLHUP.  */
 277      r = recv (fd, NULL, 0, MSG_PEEK);
 278      socket_errno = (r < 0) ? errno : 0;
 279      if (r == 0 || socket_errno == ENOTSOCK)
 280        ioctl (fd, FIONREAD, &r);
 281# else
 282      char data[64];
 283      r = recv (fd, data, sizeof (data), MSG_PEEK);
 284      socket_errno = (r < 0) ? errno : 0;
 285# endif
 286      if (r == 0)
 287        happened |= POLLHUP;
 288      /* If the event happened on an unconnected server socket,
 290         that's fine. */
 291      else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
 292        happened |= (POLLIN | POLLRDNORM) & sought;
 293      /* Distinguish hung-up sockets from other errors.  */
 295      else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
 296               || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
 297        happened |= POLLHUP;
 298      else
 300        happened |= POLLERR;
 301    }
 302  if (FD_ISSET (fd, wfds))
 304    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
 305  if (FD_ISSET (fd, efds))
 307    happened |= (POLLPRI | POLLRDBAND) & sought;
 308  return happened;
 310}
 311#endif /* !MinGW */
 312int
 314poll (pfd, nfd, timeout)
 315     struct pollfd *pfd;
 316     nfds_t nfd;
 317     int timeout;
 318{
 319#ifndef WIN32_NATIVE
 320  fd_set rfds, wfds, efds;
 321  struct timeval tv;
 322  struct timeval *ptv;
 323  int maxfd, rc;
 324  nfds_t i;
 325# ifdef _SC_OPEN_MAX
 327  static int sc_open_max = -1;
 328  if (nfd < 0
 330      || (nfd > sc_open_max
 331          && (sc_open_max != -1
 332              || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
 333    {
 334      errno = EINVAL;
 335      return -1;
 336    }
 337# else /* !_SC_OPEN_MAX */
 338#  ifdef OPEN_MAX
 339  if (nfd < 0 || nfd > OPEN_MAX)
 340    {
 341      errno = EINVAL;
 342      return -1;
 343    }
 344#  endif /* OPEN_MAX -- else, no check is needed */
 345# endif /* !_SC_OPEN_MAX */
 346  /* EFAULT is not necessary to implement, but let's do it in the
 348     simplest case. */
 349  if (!pfd)
 350    {
 351      errno = EFAULT;
 352      return -1;
 353    }
 354  /* convert timeout number into a timeval structure */
 356  if (timeout == 0)
 357    {
 358      ptv = &tv;
 359      ptv->tv_sec = 0;
 360      ptv->tv_usec = 0;
 361    }
 362  else if (timeout > 0)
 363    {
 364      ptv = &tv;
 365      ptv->tv_sec = timeout / 1000;
 366      ptv->tv_usec = (timeout % 1000) * 1000;
 367    }
 368  else if (timeout == INFTIM)
 369    /* wait forever */
 370    ptv = NULL;
 371  else
 372    {
 373      errno = EINVAL;
 374      return -1;
 375    }
 376  /* create fd sets and determine max fd */
 378  maxfd = -1;
 379  FD_ZERO (&rfds);
 380  FD_ZERO (&wfds);
 381  FD_ZERO (&efds);
 382  for (i = 0; i < nfd; i++)
 383    {
 384      if (pfd[i].fd < 0)
 385        continue;
 386      if (pfd[i].events & (POLLIN | POLLRDNORM))
 388        FD_SET (pfd[i].fd, &rfds);
 389      /* see select(2): "the only exceptional condition detectable
 391         is out-of-band data received on a socket", hence we push
 392         POLLWRBAND events onto wfds instead of efds. */
 393      if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
 394        FD_SET (pfd[i].fd, &wfds);
 395      if (pfd[i].events & (POLLPRI | POLLRDBAND))
 396        FD_SET (pfd[i].fd, &efds);
 397      if (pfd[i].fd >= maxfd
 398          && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
 399                               | POLLRDNORM | POLLRDBAND
 400                               | POLLWRNORM | POLLWRBAND)))
 401        {
 402          maxfd = pfd[i].fd;
 403          if (maxfd > FD_SETSIZE)
 404            {
 405              errno = EOVERFLOW;
 406              return -1;
 407            }
 408        }
 409    }
 410  /* examine fd sets */
 412  rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
 413  if (rc < 0)
 414    return rc;
 415  /* establish results */
 417  rc = 0;
 418  for (i = 0; i < nfd; i++)
 419    if (pfd[i].fd < 0)
 420      pfd[i].revents = 0;
 421    else
 422      {
 423        int happened = compute_revents (pfd[i].fd, pfd[i].events,
 424                                        &rfds, &wfds, &efds);
 425        if (happened)
 426          {
 427            pfd[i].revents = happened;
 428            rc++;
 429          }
 430      }
 431  return rc;
 433#else
 434  static struct timeval tv0;
 435  static HANDLE hEvent;
 436  WSANETWORKEVENTS ev;
 437  HANDLE h, handle_array[FD_SETSIZE + 2];
 438  DWORD ret, wait_timeout, nhandles;
 439  fd_set rfds, wfds, xfds;
 440  BOOL poll_again;
 441  MSG msg;
 442  int rc = 0;
 443  nfds_t i;
 444  if (nfd < 0 || timeout < -1)
 446    {
 447      errno = EINVAL;
 448      return -1;
 449    }
 450  if (!hEvent)
 452    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
 453  handle_array[0] = hEvent;
 455  nhandles = 1;
 456  FD_ZERO (&rfds);
 457  FD_ZERO (&wfds);
 458  FD_ZERO (&xfds);
 459  /* Classify socket handles and create fd sets. */
 461  for (i = 0; i < nfd; i++)
 462    {
 463      int sought = pfd[i].events;
 464      pfd[i].revents = 0;
 465      if (pfd[i].fd < 0)
 466        continue;
 467      if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
 468                      | POLLPRI | POLLRDBAND)))
 469        continue;
 470      h = (HANDLE) _get_osfhandle (pfd[i].fd);
 472      assert (h != NULL);
 473      if (IsSocketHandle (h))
 474        {
 475          int requested = FD_CLOSE;
 476          /* see above; socket handles are mapped onto select.  */
 478          if (sought & (POLLIN | POLLRDNORM))
 479            {
 480              requested |= FD_READ | FD_ACCEPT;
 481              FD_SET ((SOCKET) h, &rfds);
 482            }
 483          if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
 484            {
 485              requested |= FD_WRITE | FD_CONNECT;
 486              FD_SET ((SOCKET) h, &wfds);
 487            }
 488          if (sought & (POLLPRI | POLLRDBAND))
 489            {
 490              requested |= FD_OOB;
 491              FD_SET ((SOCKET) h, &xfds);
 492            }
 493          if (requested)
 495            WSAEventSelect ((SOCKET) h, hEvent, requested);
 496        }
 497      else
 498        {
 499          /* Poll now.  If we get an event, do not poll again.  Also,
 500             screen buffer handles are waitable, and they'll block until
 501             a character is available.  win32_compute_revents eliminates
 502             bits for the "wrong" direction. */
 503          pfd[i].revents = win32_compute_revents (h, &sought);
 504          if (sought)
 505            handle_array[nhandles++] = h;
 506          if (pfd[i].revents)
 507            timeout = 0;
 508        }
 509    }
 510  if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
 512    {
 513      /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
 514         no need to call select again.  */
 515      poll_again = FALSE;
 516      wait_timeout = 0;
 517    }
 518  else
 519    {
 520      poll_again = TRUE;
 521      if (timeout == INFTIM)
 522        wait_timeout = INFINITE;
 523      else
 524        wait_timeout = timeout;
 525    }
 526  for (;;)
 528    {
 529      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
 530                                       wait_timeout, QS_ALLINPUT);
 531      if (ret == WAIT_OBJECT_0 + nhandles)
 533        {
 534          /* new input of some other kind */
 535          BOOL bRet;
 536          while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
 537            {
 538              TranslateMessage (&msg);
 539              DispatchMessage (&msg);
 540            }
 541        }
 542      else
 543        break;
 544    }
 545  if (poll_again)
 547    select (0, &rfds, &wfds, &xfds, &tv0);
 548  /* Place a sentinel at the end of the array.  */
 550  handle_array[nhandles] = NULL;
 551  nhandles = 1;
 552  for (i = 0; i < nfd; i++)
 553    {
 554      int happened;
 555      if (pfd[i].fd < 0)
 557        continue;
 558      if (!(pfd[i].events & (POLLIN | POLLRDNORM |
 559                             POLLOUT | POLLWRNORM | POLLWRBAND)))
 560        continue;
 561      h = (HANDLE) _get_osfhandle (pfd[i].fd);
 563      if (h != handle_array[nhandles])
 564        {
 565          /* It's a socket.  */
 566          WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
 567          WSAEventSelect ((SOCKET) h, 0, 0);
 568          /* If we're lucky, WSAEnumNetworkEvents already provided a way
 570             to distinguish FD_READ and FD_ACCEPT; this saves a recv later.  */
 571          if (FD_ISSET ((SOCKET) h, &rfds)
 572              && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
 573            ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
 574          if (FD_ISSET ((SOCKET) h, &wfds))
 575            ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
 576          if (FD_ISSET ((SOCKET) h, &xfds))
 577            ev.lNetworkEvents |= FD_OOB;
 578          happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
 580                                                   ev.lNetworkEvents);
 581        }
 582      else
 583        {
 584          /* Not a socket.  */
 585          int sought = pfd[i].events;
 586          happened = win32_compute_revents (h, &sought);
 587          nhandles++;
 588        }
 589       if ((pfd[i].revents |= happened) != 0)
 591        rc++;
 592    }
 593  return rc;
 595#endif
 596}