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