7e74ebe59a5ea2e31a9100659805ada0f5d8e278
   1/* Emulation for poll(2)
   2   Contributed by Paolo Bonzini.
   3
   4   Copyright 2001-2003, 2006-2010 Free Software Foundation, Inc.
   5
   6   This file is part of gnulib.
   7
   8   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
  13   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
  18   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
  22/* 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
  27#include <malloc.h>
  28
  29#include <sys/types.h>
  30#include "poll.h"
  31#include <errno.h>
  32#include <limits.h>
  33#include <assert.h>
  34
  35#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
  49#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
  56#include <time.h>
  57
  58#ifndef INFTIM
  59# define INFTIM (-1)
  60#endif
  61
  62/* BeOS does not have MSG_PEEK.  */
  63#ifndef MSG_PEEK
  64# define MSG_PEEK 0
  65#endif
  66
  67#ifdef WIN32_NATIVE
  68
  69#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
  70
  71static BOOL
  72IsSocketHandle (HANDLE h)
  73{
  74  WSANETWORKEVENTS ev;
  75
  76  if (IsConsoleHandle (h))
  77    return FALSE;
  78
  79  /* 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
  86/* 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;
  99
 100typedef 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;
 108
 109typedef enum _FILE_INFORMATION_CLASS {
 110  FilePipeLocalInformation = 24
 111} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
 112
 113typedef DWORD (WINAPI *PNtQueryInformationFile)
 114         (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
 115
 116# ifndef PIPE_BUF
 117#  define PIPE_BUF      512
 118# endif
 119
 120/* Compute revents values for file handle H.  If some events cannot happen
 121   for the handle, eliminate them from *P_SOUGHT.  */
 122
 123static 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
 135  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
 146      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
 155      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
 167          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
 177    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
 182      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
 193          irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
 194          bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
 195          if (!bRet || avail == 0)
 196            return POLLHUP;
 197
 198          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
 210    default:
 211      ret = WaitForSingleObject (h, 0);
 212      if (ret == WAIT_OBJECT_0)
 213        return *p_sought & ~(POLLPRI | POLLRDBAND);
 214
 215      return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
 216    }
 217}
 218
 219/* Convert fd_sets returned by select into revents values.  */
 220
 221static int
 222win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
 223{
 224  int happened = 0;
 225
 226  if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
 227    happened |= (POLLIN | POLLRDNORM) & sought;
 228
 229  else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
 230    {
 231      int r, error;
 232
 233      char data[64];
 234      WSASetLastError (0);
 235      r = recv (h, data, sizeof (data), MSG_PEEK);
 236      error = WSAGetLastError ();
 237      WSASetLastError (0);
 238
 239      if (r > 0 || error == WSAENOTCONN)
 240        happened |= (POLLIN | POLLRDNORM) & sought;
 241
 242      /* 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
 247      else
 248        happened |= POLLERR;
 249    }
 250
 251  if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
 252    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
 253
 254  if (lNetworkEvents & FD_OOB)
 255    happened |= (POLLPRI | POLLRDBAND) & sought;
 256
 257  return happened;
 258}
 259
 260#else /* !MinGW */
 261
 262/* 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
 272# 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
 289      /* 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
 294      /* 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
 299      else
 300        happened |= POLLERR;
 301    }
 302
 303  if (FD_ISSET (fd, wfds))
 304    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
 305
 306  if (FD_ISSET (fd, efds))
 307    happened |= (POLLPRI | POLLRDBAND) & sought;
 308
 309  return happened;
 310}
 311#endif /* !MinGW */
 312
 313int
 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
 326# ifdef _SC_OPEN_MAX
 327  static int sc_open_max = -1;
 328
 329  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
 347  /* 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
 355  /* 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
 377  /* 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
 387      if (pfd[i].events & (POLLIN | POLLRDNORM))
 388        FD_SET (pfd[i].fd, &rfds);
 389
 390      /* 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
 411  /* examine fd sets */
 412  rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
 413  if (rc < 0)
 414    return rc;
 415
 416  /* 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
 432  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
 445  if (nfd < 0 || timeout < -1)
 446    {
 447      errno = EINVAL;
 448      return -1;
 449    }
 450
 451  if (!hEvent)
 452    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
 453
 454  handle_array[0] = hEvent;
 455  nhandles = 1;
 456  FD_ZERO (&rfds);
 457  FD_ZERO (&wfds);
 458  FD_ZERO (&xfds);
 459
 460  /* 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
 471      h = (HANDLE) _get_osfhandle (pfd[i].fd);
 472      assert (h != NULL);
 473      if (IsSocketHandle (h))
 474        {
 475          int requested = FD_CLOSE;
 476
 477          /* 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
 494          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
 511  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
 527  for (;;)
 528    {
 529      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
 530                                       wait_timeout, QS_ALLINPUT);
 531
 532      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
 546  if (poll_again)
 547    select (0, &rfds, &wfds, &xfds, &tv0);
 548
 549  /* 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
 556      if (pfd[i].fd < 0)
 557        continue;
 558      if (!(pfd[i].events & (POLLIN | POLLRDNORM |
 559                             POLLOUT | POLLWRNORM | POLLWRBAND)))
 560        continue;
 561
 562      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
 569          /* 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
 579          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
 590       if ((pfd[i].revents |= happened) != 0)
 591        rc++;
 592    }
 593
 594  return rc;
 595#endif
 596}