153a5a1b3Sopenharmony_ci
253a5a1b3Sopenharmony_ci/* Emulation for poll(2)
353a5a1b3Sopenharmony_ci   Contributed by Paolo Bonzini.
453a5a1b3Sopenharmony_ci
553a5a1b3Sopenharmony_ci   Copyright 2001-2003, 2006-2012 Free Software Foundation, Inc.
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci   This file is part of gnulib.
853a5a1b3Sopenharmony_ci
953a5a1b3Sopenharmony_ci   This program is free software; you can redistribute it and/or modify
1053a5a1b3Sopenharmony_ci   it under the terms of the GNU Lesser General Public License as published by
1153a5a1b3Sopenharmony_ci   the Free Software Foundation; either version 2.1, or (at your option)
1253a5a1b3Sopenharmony_ci   any later version.
1353a5a1b3Sopenharmony_ci
1453a5a1b3Sopenharmony_ci   This program is distributed in the hope that it will be useful,
1553a5a1b3Sopenharmony_ci   but WITHOUT ANY WARRANTY; without even the implied warranty of
1653a5a1b3Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1753a5a1b3Sopenharmony_ci   GNU Lesser General Public License for more details.
1853a5a1b3Sopenharmony_ci
1953a5a1b3Sopenharmony_ci   You should have received a copy of the GNU Lesser General Public License along
2053a5a1b3Sopenharmony_ci   with this program; if not, see <http://www.gnu.org/licenses/>.  */
2153a5a1b3Sopenharmony_ci
2253a5a1b3Sopenharmony_ci/* Tell gcc not to warn about the (nfd < 0) tests, below.  */
2353a5a1b3Sopenharmony_ci#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
2453a5a1b3Sopenharmony_ci# pragma GCC diagnostic ignored "-Wtype-limits"
2553a5a1b3Sopenharmony_ci#endif
2653a5a1b3Sopenharmony_ci
2753a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2853a5a1b3Sopenharmony_ci#include <config.h>
2953a5a1b3Sopenharmony_ci#endif
3053a5a1b3Sopenharmony_ci#include <malloc.h>
3153a5a1b3Sopenharmony_ci
3253a5a1b3Sopenharmony_ci#include <sys/types.h>
3353a5a1b3Sopenharmony_ci
3453a5a1b3Sopenharmony_ci/* Specification.  */
3553a5a1b3Sopenharmony_ci#include "poll.h"
3653a5a1b3Sopenharmony_citypedef unsigned long nfds_t;
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_ci#include <errno.h>
3953a5a1b3Sopenharmony_ci#include <limits.h>
4053a5a1b3Sopenharmony_ci#include <assert.h>
4153a5a1b3Sopenharmony_ci
4253a5a1b3Sopenharmony_ci#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
4353a5a1b3Sopenharmony_ci# define WINDOWS_NATIVE
4453a5a1b3Sopenharmony_ci# include <winsock2.h>
4553a5a1b3Sopenharmony_ci# include <windows.h>
4653a5a1b3Sopenharmony_ci# include <io.h>
4753a5a1b3Sopenharmony_ci# include <stdio.h>
4853a5a1b3Sopenharmony_ci# include <conio.h>
4953a5a1b3Sopenharmony_ci# include <signal.h>
5053a5a1b3Sopenharmony_ci# if 0
5153a5a1b3Sopenharmony_ci# include "msvc-nothrow.h"
5253a5a1b3Sopenharmony_ci# endif
5353a5a1b3Sopenharmony_ci#else
5453a5a1b3Sopenharmony_ci# include <sys/time.h>
5553a5a1b3Sopenharmony_ci# include <sys/socket.h>
5653a5a1b3Sopenharmony_ci# include <sys/select.h>
5753a5a1b3Sopenharmony_ci# include <unistd.h>
5853a5a1b3Sopenharmony_ci#endif
5953a5a1b3Sopenharmony_ci
6053a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H
6153a5a1b3Sopenharmony_ci# include <sys/ioctl.h>
6253a5a1b3Sopenharmony_ci#endif
6353a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_FILIO_H
6453a5a1b3Sopenharmony_ci# include <sys/filio.h>
6553a5a1b3Sopenharmony_ci#endif
6653a5a1b3Sopenharmony_ci
6753a5a1b3Sopenharmony_ci#include <time.h>
6853a5a1b3Sopenharmony_ci
6953a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
7053a5a1b3Sopenharmony_ci
7153a5a1b3Sopenharmony_ci#ifndef INFTIM
7253a5a1b3Sopenharmony_ci# define INFTIM (-1)
7353a5a1b3Sopenharmony_ci#endif
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_ci/* BeOS does not have MSG_PEEK.  */
7653a5a1b3Sopenharmony_ci#ifndef MSG_PEEK
7753a5a1b3Sopenharmony_ci# define MSG_PEEK 0
7853a5a1b3Sopenharmony_ci#endif
7953a5a1b3Sopenharmony_ci
8053a5a1b3Sopenharmony_ci#ifndef POLLRDNORM
8153a5a1b3Sopenharmony_ci# define POLLRDNORM  0
8253a5a1b3Sopenharmony_ci# define POLLRDBAND  0
8353a5a1b3Sopenharmony_ci# define POLLWRNORM  0
8453a5a1b3Sopenharmony_ci# define POLLWRBAND  0
8553a5a1b3Sopenharmony_ci#endif
8653a5a1b3Sopenharmony_ci
8753a5a1b3Sopenharmony_ci#ifdef WINDOWS_NATIVE
8853a5a1b3Sopenharmony_ci
8953a5a1b3Sopenharmony_ci/* Optimized test whether a HANDLE refers to a console.
9053a5a1b3Sopenharmony_ci   See <http://lists.gnu.org/archive/html/bug-gnulib/2009-08/msg00065.html>.  */
9153a5a1b3Sopenharmony_ci#define IsConsoleHandle(h) (((intptr_t) (h) & 3) == 3)
9253a5a1b3Sopenharmony_ci
9353a5a1b3Sopenharmony_cistatic BOOL
9453a5a1b3Sopenharmony_ciIsSocketHandle (HANDLE h)
9553a5a1b3Sopenharmony_ci{
9653a5a1b3Sopenharmony_ci  WSANETWORKEVENTS ev;
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_ci  if (IsConsoleHandle (h))
9953a5a1b3Sopenharmony_ci    return FALSE;
10053a5a1b3Sopenharmony_ci
10153a5a1b3Sopenharmony_ci  /* Under Wine, it seems that getsockopt returns 0 for pipes too.
10253a5a1b3Sopenharmony_ci     WSAEnumNetworkEvents instead distinguishes the two correctly.  */
10353a5a1b3Sopenharmony_ci  ev.lNetworkEvents = 0xDEADBEEFl;
10453a5a1b3Sopenharmony_ci  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
10553a5a1b3Sopenharmony_ci  return ev.lNetworkEvents != 0xDEADBEEFl;
10653a5a1b3Sopenharmony_ci}
10753a5a1b3Sopenharmony_ci
10853a5a1b3Sopenharmony_cistatic HANDLE
10953a5a1b3Sopenharmony_ciHandleFromFd (int fd)
11053a5a1b3Sopenharmony_ci{
11153a5a1b3Sopenharmony_ci  /* since socket() returns a HANDLE already, try that first */
11253a5a1b3Sopenharmony_ci  if (IsSocketHandle(PA_INT_TO_PTR(fd)))
11353a5a1b3Sopenharmony_ci    return PA_INT_TO_PTR(fd);
11453a5a1b3Sopenharmony_ci
11553a5a1b3Sopenharmony_ci  return ((HANDLE) _get_osfhandle(fd));
11653a5a1b3Sopenharmony_ci}
11753a5a1b3Sopenharmony_ci
11853a5a1b3Sopenharmony_ci/* Declare data structures for ntdll functions.  */
11953a5a1b3Sopenharmony_citypedef struct _FILE_PIPE_LOCAL_INFORMATION {
12053a5a1b3Sopenharmony_ci  ULONG NamedPipeType;
12153a5a1b3Sopenharmony_ci  ULONG NamedPipeConfiguration;
12253a5a1b3Sopenharmony_ci  ULONG MaximumInstances;
12353a5a1b3Sopenharmony_ci  ULONG CurrentInstances;
12453a5a1b3Sopenharmony_ci  ULONG InboundQuota;
12553a5a1b3Sopenharmony_ci  ULONG ReadDataAvailable;
12653a5a1b3Sopenharmony_ci  ULONG OutboundQuota;
12753a5a1b3Sopenharmony_ci  ULONG WriteQuotaAvailable;
12853a5a1b3Sopenharmony_ci  ULONG NamedPipeState;
12953a5a1b3Sopenharmony_ci  ULONG NamedPipeEnd;
13053a5a1b3Sopenharmony_ci} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
13153a5a1b3Sopenharmony_ci
13253a5a1b3Sopenharmony_citypedef struct _IO_STATUS_BLOCK
13353a5a1b3Sopenharmony_ci{
13453a5a1b3Sopenharmony_ci  union {
13553a5a1b3Sopenharmony_ci    DWORD Status;
13653a5a1b3Sopenharmony_ci    PVOID Pointer;
13753a5a1b3Sopenharmony_ci  } u;
13853a5a1b3Sopenharmony_ci  ULONG_PTR Information;
13953a5a1b3Sopenharmony_ci} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
14053a5a1b3Sopenharmony_ci
14153a5a1b3Sopenharmony_citypedef enum _FILE_INFORMATION_CLASS {
14253a5a1b3Sopenharmony_ci  FilePipeLocalInformation = 24
14353a5a1b3Sopenharmony_ci} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
14453a5a1b3Sopenharmony_ci
14553a5a1b3Sopenharmony_citypedef DWORD (WINAPI *PNtQueryInformationFile)
14653a5a1b3Sopenharmony_ci         (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
14753a5a1b3Sopenharmony_ci
14853a5a1b3Sopenharmony_ci# ifndef PIPE_BUF
14953a5a1b3Sopenharmony_ci#  define PIPE_BUF      512
15053a5a1b3Sopenharmony_ci# endif
15153a5a1b3Sopenharmony_ci
15253a5a1b3Sopenharmony_ci/* Compute revents values for file handle H.  If some events cannot happen
15353a5a1b3Sopenharmony_ci   for the handle, eliminate them from *P_SOUGHT.  */
15453a5a1b3Sopenharmony_ci
15553a5a1b3Sopenharmony_cistatic int
15653a5a1b3Sopenharmony_ciwindows_compute_revents (HANDLE h, int *p_sought)
15753a5a1b3Sopenharmony_ci{
15853a5a1b3Sopenharmony_ci  int i, ret, happened;
15953a5a1b3Sopenharmony_ci  INPUT_RECORD *irbuffer;
16053a5a1b3Sopenharmony_ci  DWORD avail, nbuffer;
16153a5a1b3Sopenharmony_ci  BOOL bRet;
16253a5a1b3Sopenharmony_ci  IO_STATUS_BLOCK iosb;
16353a5a1b3Sopenharmony_ci  FILE_PIPE_LOCAL_INFORMATION fpli;
16453a5a1b3Sopenharmony_ci  static PNtQueryInformationFile NtQueryInformationFile;
16553a5a1b3Sopenharmony_ci  static BOOL once_only;
16653a5a1b3Sopenharmony_ci
16753a5a1b3Sopenharmony_ci  switch (GetFileType (h))
16853a5a1b3Sopenharmony_ci    {
16953a5a1b3Sopenharmony_ci    case FILE_TYPE_PIPE:
17053a5a1b3Sopenharmony_ci      if (!once_only)
17153a5a1b3Sopenharmony_ci        {
17253a5a1b3Sopenharmony_ci          NtQueryInformationFile = (PNtQueryInformationFile)
17353a5a1b3Sopenharmony_ci            GetProcAddress (GetModuleHandle ("ntdll.dll"),
17453a5a1b3Sopenharmony_ci                            "NtQueryInformationFile");
17553a5a1b3Sopenharmony_ci          once_only = TRUE;
17653a5a1b3Sopenharmony_ci        }
17753a5a1b3Sopenharmony_ci
17853a5a1b3Sopenharmony_ci      happened = 0;
17953a5a1b3Sopenharmony_ci      if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
18053a5a1b3Sopenharmony_ci        {
18153a5a1b3Sopenharmony_ci          if (avail)
18253a5a1b3Sopenharmony_ci            happened |= *p_sought & (POLLIN | POLLRDNORM);
18353a5a1b3Sopenharmony_ci        }
18453a5a1b3Sopenharmony_ci      else if (GetLastError () == ERROR_BROKEN_PIPE)
18553a5a1b3Sopenharmony_ci        happened |= POLLHUP;
18653a5a1b3Sopenharmony_ci
18753a5a1b3Sopenharmony_ci      else
18853a5a1b3Sopenharmony_ci        {
18953a5a1b3Sopenharmony_ci          /* It was the write-end of the pipe.  Check if it is writable.
19053a5a1b3Sopenharmony_ci             If NtQueryInformationFile fails, optimistically assume the pipe is
19153a5a1b3Sopenharmony_ci             writable.  This could happen on Windows 9x, where
19253a5a1b3Sopenharmony_ci             NtQueryInformationFile is not available, or if we inherit a pipe
19353a5a1b3Sopenharmony_ci             that doesn't permit FILE_READ_ATTRIBUTES access on the write end
19453a5a1b3Sopenharmony_ci             (I think this should not happen since Windows XP SP2; WINE seems
19553a5a1b3Sopenharmony_ci             fine too).  Otherwise, ensure that enough space is available for
19653a5a1b3Sopenharmony_ci             atomic writes.  */
19753a5a1b3Sopenharmony_ci          memset (&iosb, 0, sizeof (iosb));
19853a5a1b3Sopenharmony_ci          memset (&fpli, 0, sizeof (fpli));
19953a5a1b3Sopenharmony_ci
20053a5a1b3Sopenharmony_ci          if (!NtQueryInformationFile
20153a5a1b3Sopenharmony_ci              || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
20253a5a1b3Sopenharmony_ci                                         FilePipeLocalInformation)
20353a5a1b3Sopenharmony_ci              || fpli.WriteQuotaAvailable >= PIPE_BUF
20453a5a1b3Sopenharmony_ci              || (fpli.OutboundQuota < PIPE_BUF &&
20553a5a1b3Sopenharmony_ci                  fpli.WriteQuotaAvailable == fpli.OutboundQuota))
20653a5a1b3Sopenharmony_ci            happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
20753a5a1b3Sopenharmony_ci        }
20853a5a1b3Sopenharmony_ci      return happened;
20953a5a1b3Sopenharmony_ci
21053a5a1b3Sopenharmony_ci    case FILE_TYPE_CHAR:
21153a5a1b3Sopenharmony_ci      ret = WaitForSingleObject (h, 0);
21253a5a1b3Sopenharmony_ci      if (!IsConsoleHandle (h))
21353a5a1b3Sopenharmony_ci        return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
21453a5a1b3Sopenharmony_ci
21553a5a1b3Sopenharmony_ci      nbuffer = avail = 0;
21653a5a1b3Sopenharmony_ci      bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
21753a5a1b3Sopenharmony_ci      if (bRet)
21853a5a1b3Sopenharmony_ci        {
21953a5a1b3Sopenharmony_ci          /* Input buffer.  */
22053a5a1b3Sopenharmony_ci          *p_sought &= POLLIN | POLLRDNORM;
22153a5a1b3Sopenharmony_ci          if (nbuffer == 0)
22253a5a1b3Sopenharmony_ci            return POLLHUP;
22353a5a1b3Sopenharmony_ci          if (!*p_sought)
22453a5a1b3Sopenharmony_ci            return 0;
22553a5a1b3Sopenharmony_ci
22653a5a1b3Sopenharmony_ci          irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
22753a5a1b3Sopenharmony_ci          bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
22853a5a1b3Sopenharmony_ci          if (!bRet || avail == 0)
22953a5a1b3Sopenharmony_ci            return POLLHUP;
23053a5a1b3Sopenharmony_ci
23153a5a1b3Sopenharmony_ci          for (i = 0; i < avail; i++)
23253a5a1b3Sopenharmony_ci            if (irbuffer[i].EventType == KEY_EVENT)
23353a5a1b3Sopenharmony_ci              return *p_sought;
23453a5a1b3Sopenharmony_ci          return 0;
23553a5a1b3Sopenharmony_ci        }
23653a5a1b3Sopenharmony_ci      else
23753a5a1b3Sopenharmony_ci        {
23853a5a1b3Sopenharmony_ci          /* Screen buffer.  */
23953a5a1b3Sopenharmony_ci          *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
24053a5a1b3Sopenharmony_ci          return *p_sought;
24153a5a1b3Sopenharmony_ci        }
24253a5a1b3Sopenharmony_ci
24353a5a1b3Sopenharmony_ci    default:
24453a5a1b3Sopenharmony_ci      ret = WaitForSingleObject (h, 0);
24553a5a1b3Sopenharmony_ci      if (ret == WAIT_OBJECT_0)
24653a5a1b3Sopenharmony_ci        return *p_sought & ~(POLLPRI | POLLRDBAND);
24753a5a1b3Sopenharmony_ci
24853a5a1b3Sopenharmony_ci      return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
24953a5a1b3Sopenharmony_ci    }
25053a5a1b3Sopenharmony_ci}
25153a5a1b3Sopenharmony_ci
25253a5a1b3Sopenharmony_ci/* Convert fd_sets returned by select into revents values.  */
25353a5a1b3Sopenharmony_ci
25453a5a1b3Sopenharmony_cistatic int
25553a5a1b3Sopenharmony_ciwindows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
25653a5a1b3Sopenharmony_ci{
25753a5a1b3Sopenharmony_ci  int happened = 0;
25853a5a1b3Sopenharmony_ci
25953a5a1b3Sopenharmony_ci  if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
26053a5a1b3Sopenharmony_ci    happened |= (POLLIN | POLLRDNORM) & sought;
26153a5a1b3Sopenharmony_ci
26253a5a1b3Sopenharmony_ci  else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
26353a5a1b3Sopenharmony_ci    {
26453a5a1b3Sopenharmony_ci      int r, error;
26553a5a1b3Sopenharmony_ci
26653a5a1b3Sopenharmony_ci      char data[64];
26753a5a1b3Sopenharmony_ci      WSASetLastError (0);
26853a5a1b3Sopenharmony_ci      r = recv (h, data, sizeof (data), MSG_PEEK);
26953a5a1b3Sopenharmony_ci      error = WSAGetLastError ();
27053a5a1b3Sopenharmony_ci      WSASetLastError (0);
27153a5a1b3Sopenharmony_ci
27253a5a1b3Sopenharmony_ci      if (r > 0 || error == WSAENOTCONN)
27353a5a1b3Sopenharmony_ci        happened |= (POLLIN | POLLRDNORM) & sought;
27453a5a1b3Sopenharmony_ci
27553a5a1b3Sopenharmony_ci      /* Distinguish hung-up sockets from other errors.  */
27653a5a1b3Sopenharmony_ci      else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
27753a5a1b3Sopenharmony_ci               || error == WSAECONNABORTED || error == WSAENETRESET)
27853a5a1b3Sopenharmony_ci        happened |= POLLHUP;
27953a5a1b3Sopenharmony_ci
28053a5a1b3Sopenharmony_ci      else
28153a5a1b3Sopenharmony_ci        happened |= POLLERR;
28253a5a1b3Sopenharmony_ci    }
28353a5a1b3Sopenharmony_ci
28453a5a1b3Sopenharmony_ci  if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
28553a5a1b3Sopenharmony_ci    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
28653a5a1b3Sopenharmony_ci
28753a5a1b3Sopenharmony_ci  if (lNetworkEvents & FD_OOB)
28853a5a1b3Sopenharmony_ci    happened |= (POLLPRI | POLLRDBAND) & sought;
28953a5a1b3Sopenharmony_ci
29053a5a1b3Sopenharmony_ci  return happened;
29153a5a1b3Sopenharmony_ci}
29253a5a1b3Sopenharmony_ci
29353a5a1b3Sopenharmony_ci#else /* !MinGW */
29453a5a1b3Sopenharmony_ci
29553a5a1b3Sopenharmony_ci/* Convert select(2) returned fd_sets into poll(2) revents values.  */
29653a5a1b3Sopenharmony_cistatic int
29753a5a1b3Sopenharmony_cicompute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
29853a5a1b3Sopenharmony_ci{
29953a5a1b3Sopenharmony_ci  int happened = 0;
30053a5a1b3Sopenharmony_ci  if (FD_ISSET (fd, rfds))
30153a5a1b3Sopenharmony_ci    {
30253a5a1b3Sopenharmony_ci      int r;
30353a5a1b3Sopenharmony_ci      int socket_errno;
30453a5a1b3Sopenharmony_ci
30553a5a1b3Sopenharmony_ci# if defined __MACH__ && defined __APPLE__
30653a5a1b3Sopenharmony_ci      /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
30753a5a1b3Sopenharmony_ci         for some kinds of descriptors.  Detect if this descriptor is a
30853a5a1b3Sopenharmony_ci         connected socket, a server socket, or something else using a
30953a5a1b3Sopenharmony_ci         0-byte recv, and use ioctl(2) to detect POLLHUP.  */
31053a5a1b3Sopenharmony_ci      r = recv (fd, NULL, 0, MSG_PEEK);
31153a5a1b3Sopenharmony_ci      socket_errno = (r < 0) ? errno : 0;
31253a5a1b3Sopenharmony_ci      if (r == 0 || socket_errno == ENOTSOCK)
31353a5a1b3Sopenharmony_ci        ioctl (fd, FIONREAD, &r);
31453a5a1b3Sopenharmony_ci# else
31553a5a1b3Sopenharmony_ci      char data[64];
31653a5a1b3Sopenharmony_ci      r = recv (fd, data, sizeof (data), MSG_PEEK);
31753a5a1b3Sopenharmony_ci      socket_errno = (r < 0) ? errno : 0;
31853a5a1b3Sopenharmony_ci# endif
31953a5a1b3Sopenharmony_ci      if (r == 0)
32053a5a1b3Sopenharmony_ci        happened |= POLLHUP;
32153a5a1b3Sopenharmony_ci
32253a5a1b3Sopenharmony_ci      /* If the event happened on an unconnected server socket,
32353a5a1b3Sopenharmony_ci         that's fine. */
32453a5a1b3Sopenharmony_ci      else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
32553a5a1b3Sopenharmony_ci        happened |= (POLLIN | POLLRDNORM) & sought;
32653a5a1b3Sopenharmony_ci
32753a5a1b3Sopenharmony_ci      /* Distinguish hung-up sockets from other errors.  */
32853a5a1b3Sopenharmony_ci      else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
32953a5a1b3Sopenharmony_ci               || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
33053a5a1b3Sopenharmony_ci        happened |= POLLHUP;
33153a5a1b3Sopenharmony_ci
33253a5a1b3Sopenharmony_ci      /* some systems can't use recv() on non-socket, including HP NonStop */
33353a5a1b3Sopenharmony_ci      else if (socket_errno == ENOTSOCK)
33453a5a1b3Sopenharmony_ci        happened |= (POLLIN | POLLRDNORM) & sought;
33553a5a1b3Sopenharmony_ci
33653a5a1b3Sopenharmony_ci      else
33753a5a1b3Sopenharmony_ci        happened |= POLLERR;
33853a5a1b3Sopenharmony_ci    }
33953a5a1b3Sopenharmony_ci
34053a5a1b3Sopenharmony_ci  if (FD_ISSET (fd, wfds))
34153a5a1b3Sopenharmony_ci    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
34253a5a1b3Sopenharmony_ci
34353a5a1b3Sopenharmony_ci  if (FD_ISSET (fd, efds))
34453a5a1b3Sopenharmony_ci    happened |= (POLLPRI | POLLRDBAND) & sought;
34553a5a1b3Sopenharmony_ci
34653a5a1b3Sopenharmony_ci  return happened;
34753a5a1b3Sopenharmony_ci}
34853a5a1b3Sopenharmony_ci#endif /* !MinGW */
34953a5a1b3Sopenharmony_ci
35053a5a1b3Sopenharmony_ciint
35153a5a1b3Sopenharmony_cipa_poll (struct pollfd *pfd, nfds_t nfd, int timeout)
35253a5a1b3Sopenharmony_ci{
35353a5a1b3Sopenharmony_ci  struct timeval tv;
35453a5a1b3Sopenharmony_ci
35553a5a1b3Sopenharmony_ci#ifndef WINDOWS_NATIVE
35653a5a1b3Sopenharmony_ci  struct timeval *ptv;
35753a5a1b3Sopenharmony_ci  fd_set rfds, wfds, efds;
35853a5a1b3Sopenharmony_ci  int maxfd, rc;
35953a5a1b3Sopenharmony_ci  nfds_t i;
36053a5a1b3Sopenharmony_ci
36153a5a1b3Sopenharmony_ci# ifdef _SC_OPEN_MAX
36253a5a1b3Sopenharmony_ci  static int sc_open_max = -1;
36353a5a1b3Sopenharmony_ci
36453a5a1b3Sopenharmony_ci  if (nfd < 0
36553a5a1b3Sopenharmony_ci      || (nfd > sc_open_max
36653a5a1b3Sopenharmony_ci          && (sc_open_max != -1
36753a5a1b3Sopenharmony_ci              || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
36853a5a1b3Sopenharmony_ci    {
36953a5a1b3Sopenharmony_ci      errno = EINVAL;
37053a5a1b3Sopenharmony_ci      return -1;
37153a5a1b3Sopenharmony_ci    }
37253a5a1b3Sopenharmony_ci# else /* !_SC_OPEN_MAX */
37353a5a1b3Sopenharmony_ci#  ifdef OPEN_MAX
37453a5a1b3Sopenharmony_ci  if (nfd < 0 || nfd > OPEN_MAX)
37553a5a1b3Sopenharmony_ci    {
37653a5a1b3Sopenharmony_ci      errno = EINVAL;
37753a5a1b3Sopenharmony_ci      return -1;
37853a5a1b3Sopenharmony_ci    }
37953a5a1b3Sopenharmony_ci#  endif /* OPEN_MAX -- else, no check is needed */
38053a5a1b3Sopenharmony_ci# endif /* !_SC_OPEN_MAX */
38153a5a1b3Sopenharmony_ci
38253a5a1b3Sopenharmony_ci  /* EFAULT is not necessary to implement, but let's do it in the
38353a5a1b3Sopenharmony_ci     simplest case. */
38453a5a1b3Sopenharmony_ci  if (!pfd && nfd)
38553a5a1b3Sopenharmony_ci    {
38653a5a1b3Sopenharmony_ci      errno = EFAULT;
38753a5a1b3Sopenharmony_ci      return -1;
38853a5a1b3Sopenharmony_ci    }
38953a5a1b3Sopenharmony_ci
39053a5a1b3Sopenharmony_ci  /* convert timeout number into a timeval structure */
39153a5a1b3Sopenharmony_ci  if (timeout == 0)
39253a5a1b3Sopenharmony_ci    {
39353a5a1b3Sopenharmony_ci      ptv = &tv;
39453a5a1b3Sopenharmony_ci      ptv->tv_sec = 0;
39553a5a1b3Sopenharmony_ci      ptv->tv_usec = 0;
39653a5a1b3Sopenharmony_ci    }
39753a5a1b3Sopenharmony_ci  else if (timeout > 0)
39853a5a1b3Sopenharmony_ci    {
39953a5a1b3Sopenharmony_ci      ptv = &tv;
40053a5a1b3Sopenharmony_ci      ptv->tv_sec = timeout / 1000;
40153a5a1b3Sopenharmony_ci      ptv->tv_usec = (timeout % 1000) * 1000;
40253a5a1b3Sopenharmony_ci    }
40353a5a1b3Sopenharmony_ci  else if (timeout == INFTIM)
40453a5a1b3Sopenharmony_ci    /* wait forever */
40553a5a1b3Sopenharmony_ci    ptv = NULL;
40653a5a1b3Sopenharmony_ci  else
40753a5a1b3Sopenharmony_ci    {
40853a5a1b3Sopenharmony_ci      errno = EINVAL;
40953a5a1b3Sopenharmony_ci      return -1;
41053a5a1b3Sopenharmony_ci    }
41153a5a1b3Sopenharmony_ci
41253a5a1b3Sopenharmony_ci  /* create fd sets and determine max fd */
41353a5a1b3Sopenharmony_ci  maxfd = -1;
41453a5a1b3Sopenharmony_ci  FD_ZERO (&rfds);
41553a5a1b3Sopenharmony_ci  FD_ZERO (&wfds);
41653a5a1b3Sopenharmony_ci  FD_ZERO (&efds);
41753a5a1b3Sopenharmony_ci  for (i = 0; i < nfd; i++)
41853a5a1b3Sopenharmony_ci    {
41953a5a1b3Sopenharmony_ci      if (pfd[i].fd < 0)
42053a5a1b3Sopenharmony_ci        continue;
42153a5a1b3Sopenharmony_ci
42253a5a1b3Sopenharmony_ci      if (pfd[i].events & (POLLIN | POLLRDNORM))
42353a5a1b3Sopenharmony_ci        FD_SET (pfd[i].fd, &rfds);
42453a5a1b3Sopenharmony_ci
42553a5a1b3Sopenharmony_ci      /* see select(2): "the only exceptional condition detectable
42653a5a1b3Sopenharmony_ci         is out-of-band data received on a socket", hence we push
42753a5a1b3Sopenharmony_ci         POLLWRBAND events onto wfds instead of efds. */
42853a5a1b3Sopenharmony_ci      if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
42953a5a1b3Sopenharmony_ci        FD_SET (pfd[i].fd, &wfds);
43053a5a1b3Sopenharmony_ci      if (pfd[i].events & (POLLPRI | POLLRDBAND))
43153a5a1b3Sopenharmony_ci        FD_SET (pfd[i].fd, &efds);
43253a5a1b3Sopenharmony_ci      if (pfd[i].fd >= maxfd
43353a5a1b3Sopenharmony_ci          && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
43453a5a1b3Sopenharmony_ci                               | POLLRDNORM | POLLRDBAND
43553a5a1b3Sopenharmony_ci                               | POLLWRNORM | POLLWRBAND)))
43653a5a1b3Sopenharmony_ci        {
43753a5a1b3Sopenharmony_ci          maxfd = pfd[i].fd;
43853a5a1b3Sopenharmony_ci          if (maxfd > FD_SETSIZE)
43953a5a1b3Sopenharmony_ci            {
44053a5a1b3Sopenharmony_ci              errno = EOVERFLOW;
44153a5a1b3Sopenharmony_ci              return -1;
44253a5a1b3Sopenharmony_ci            }
44353a5a1b3Sopenharmony_ci        }
44453a5a1b3Sopenharmony_ci    }
44553a5a1b3Sopenharmony_ci
44653a5a1b3Sopenharmony_ci  /* examine fd sets */
44753a5a1b3Sopenharmony_ci  rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
44853a5a1b3Sopenharmony_ci  if (rc < 0)
44953a5a1b3Sopenharmony_ci    return rc;
45053a5a1b3Sopenharmony_ci
45153a5a1b3Sopenharmony_ci  /* establish results */
45253a5a1b3Sopenharmony_ci  rc = 0;
45353a5a1b3Sopenharmony_ci  for (i = 0; i < nfd; i++)
45453a5a1b3Sopenharmony_ci    if (pfd[i].fd < 0)
45553a5a1b3Sopenharmony_ci      pfd[i].revents = 0;
45653a5a1b3Sopenharmony_ci    else
45753a5a1b3Sopenharmony_ci      {
45853a5a1b3Sopenharmony_ci        int happened = compute_revents (pfd[i].fd, pfd[i].events,
45953a5a1b3Sopenharmony_ci                                        &rfds, &wfds, &efds);
46053a5a1b3Sopenharmony_ci        if (happened)
46153a5a1b3Sopenharmony_ci          {
46253a5a1b3Sopenharmony_ci            pfd[i].revents = happened;
46353a5a1b3Sopenharmony_ci            rc++;
46453a5a1b3Sopenharmony_ci          }
46553a5a1b3Sopenharmony_ci      }
46653a5a1b3Sopenharmony_ci
46753a5a1b3Sopenharmony_ci  return rc;
46853a5a1b3Sopenharmony_ci#else /* WINDOWS_NATIVE*/
46953a5a1b3Sopenharmony_ci  HANDLE hEvent;
47053a5a1b3Sopenharmony_ci  WSANETWORKEVENTS ev;
47153a5a1b3Sopenharmony_ci  HANDLE h, handle_array[FD_SETSIZE + 2];
47253a5a1b3Sopenharmony_ci  DWORD ret, wait_timeout, nhandles;
47353a5a1b3Sopenharmony_ci  fd_set rfds, wfds, xfds;
47453a5a1b3Sopenharmony_ci  BOOL poll_again;
47553a5a1b3Sopenharmony_ci  MSG msg;
47653a5a1b3Sopenharmony_ci  int rc = 0;
47753a5a1b3Sopenharmony_ci  nfds_t i;
47853a5a1b3Sopenharmony_ci
47953a5a1b3Sopenharmony_ci  hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
48053a5a1b3Sopenharmony_ci
48153a5a1b3Sopenharmony_cirestart:
48253a5a1b3Sopenharmony_ci  handle_array[0] = hEvent;
48353a5a1b3Sopenharmony_ci  nhandles = 1;
48453a5a1b3Sopenharmony_ci  FD_ZERO (&rfds);
48553a5a1b3Sopenharmony_ci  FD_ZERO (&wfds);
48653a5a1b3Sopenharmony_ci  FD_ZERO (&xfds);
48753a5a1b3Sopenharmony_ci
48853a5a1b3Sopenharmony_ci  /* Classify socket handles and create fd sets. */
48953a5a1b3Sopenharmony_ci  for (i = 0; i < nfd; i++)
49053a5a1b3Sopenharmony_ci    {
49153a5a1b3Sopenharmony_ci      int sought = pfd[i].events;
49253a5a1b3Sopenharmony_ci      pfd[i].revents = 0;
49353a5a1b3Sopenharmony_ci      if (pfd[i].fd < 0)
49453a5a1b3Sopenharmony_ci        continue;
49553a5a1b3Sopenharmony_ci      if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
49653a5a1b3Sopenharmony_ci                      | POLLPRI | POLLRDBAND)))
49753a5a1b3Sopenharmony_ci        continue;
49853a5a1b3Sopenharmony_ci
49953a5a1b3Sopenharmony_ci      h = HandleFromFd (pfd[i].fd);
50053a5a1b3Sopenharmony_ci      assert (h != NULL && h != INVALID_HANDLE_VALUE);
50153a5a1b3Sopenharmony_ci      if (IsSocketHandle (h))
50253a5a1b3Sopenharmony_ci        {
50353a5a1b3Sopenharmony_ci          int requested = FD_CLOSE;
50453a5a1b3Sopenharmony_ci
50553a5a1b3Sopenharmony_ci          /* see above; socket handles are mapped onto select.  */
50653a5a1b3Sopenharmony_ci          if (sought & (POLLIN | POLLRDNORM))
50753a5a1b3Sopenharmony_ci            {
50853a5a1b3Sopenharmony_ci              requested |= FD_READ | FD_ACCEPT;
50953a5a1b3Sopenharmony_ci              FD_SET ((SOCKET) h, &rfds);
51053a5a1b3Sopenharmony_ci            }
51153a5a1b3Sopenharmony_ci          if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
51253a5a1b3Sopenharmony_ci            {
51353a5a1b3Sopenharmony_ci              requested |= FD_WRITE | FD_CONNECT;
51453a5a1b3Sopenharmony_ci              FD_SET ((SOCKET) h, &wfds);
51553a5a1b3Sopenharmony_ci            }
51653a5a1b3Sopenharmony_ci          if (sought & (POLLPRI | POLLRDBAND))
51753a5a1b3Sopenharmony_ci            {
51853a5a1b3Sopenharmony_ci              requested |= FD_OOB;
51953a5a1b3Sopenharmony_ci              FD_SET ((SOCKET) h, &xfds);
52053a5a1b3Sopenharmony_ci            }
52153a5a1b3Sopenharmony_ci
52253a5a1b3Sopenharmony_ci          if (requested)
52353a5a1b3Sopenharmony_ci            WSAEventSelect ((SOCKET) h, hEvent, requested);
52453a5a1b3Sopenharmony_ci        }
52553a5a1b3Sopenharmony_ci      else
52653a5a1b3Sopenharmony_ci        {
52753a5a1b3Sopenharmony_ci          /* Poll now.  If we get an event, do not poll again.  Also,
52853a5a1b3Sopenharmony_ci             screen buffer handles are waitable, and they'll block until
52953a5a1b3Sopenharmony_ci             a character is available.  windows_compute_revents eliminates
53053a5a1b3Sopenharmony_ci             bits for the "wrong" direction. */
53153a5a1b3Sopenharmony_ci          pfd[i].revents = windows_compute_revents (h, &sought);
53253a5a1b3Sopenharmony_ci          if (sought)
53353a5a1b3Sopenharmony_ci            handle_array[nhandles++] = h;
53453a5a1b3Sopenharmony_ci          if (pfd[i].revents)
53553a5a1b3Sopenharmony_ci            timeout = 0;
53653a5a1b3Sopenharmony_ci        }
53753a5a1b3Sopenharmony_ci    }
53853a5a1b3Sopenharmony_ci
53953a5a1b3Sopenharmony_ci  /* We poll current status using select(). It cannot be used to check
54053a5a1b3Sopenharmony_ci     anything but sockets, so we still have to wait in
54153a5a1b3Sopenharmony_ci     MsgWaitForMultipleObjects(). But that in turn cannot check existing
54253a5a1b3Sopenharmony_ci     state, so we can't remove this select(). */
54353a5a1b3Sopenharmony_ci  /* FIXME: MSDN states that we cannot give empty fd_set:s. */
54453a5a1b3Sopenharmony_ci  tv.tv_sec = tv.tv_usec = 0;
54553a5a1b3Sopenharmony_ci  if (select (0, &rfds, &wfds, &xfds, &tv) > 0)
54653a5a1b3Sopenharmony_ci    {
54753a5a1b3Sopenharmony_ci      /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
54853a5a1b3Sopenharmony_ci         no need to call select again.  */
54953a5a1b3Sopenharmony_ci      poll_again = FALSE;
55053a5a1b3Sopenharmony_ci      wait_timeout = 0;
55153a5a1b3Sopenharmony_ci    }
55253a5a1b3Sopenharmony_ci  else
55353a5a1b3Sopenharmony_ci    {
55453a5a1b3Sopenharmony_ci      poll_again = TRUE;
55553a5a1b3Sopenharmony_ci      if (timeout == INFTIM)
55653a5a1b3Sopenharmony_ci        wait_timeout = INFINITE;
55753a5a1b3Sopenharmony_ci      else
55853a5a1b3Sopenharmony_ci        wait_timeout = timeout;
55953a5a1b3Sopenharmony_ci    }
56053a5a1b3Sopenharmony_ci
56153a5a1b3Sopenharmony_ci  for (;;)
56253a5a1b3Sopenharmony_ci    {
56353a5a1b3Sopenharmony_ci      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
56453a5a1b3Sopenharmony_ci                                       wait_timeout, QS_ALLINPUT);
56553a5a1b3Sopenharmony_ci
56653a5a1b3Sopenharmony_ci      if (ret == WAIT_OBJECT_0 + nhandles)
56753a5a1b3Sopenharmony_ci        {
56853a5a1b3Sopenharmony_ci          /* new input of some other kind */
56953a5a1b3Sopenharmony_ci          BOOL bRet;
57053a5a1b3Sopenharmony_ci          while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
57153a5a1b3Sopenharmony_ci            {
57253a5a1b3Sopenharmony_ci              if (msg.message == WM_QUIT)
57353a5a1b3Sopenharmony_ci                  raise(SIGTERM);
57453a5a1b3Sopenharmony_ci              else
57553a5a1b3Sopenharmony_ci                {
57653a5a1b3Sopenharmony_ci                  TranslateMessage (&msg);
57753a5a1b3Sopenharmony_ci                  DispatchMessage (&msg);
57853a5a1b3Sopenharmony_ci                }
57953a5a1b3Sopenharmony_ci            }
58053a5a1b3Sopenharmony_ci        }
58153a5a1b3Sopenharmony_ci      else
58253a5a1b3Sopenharmony_ci        break;
58353a5a1b3Sopenharmony_ci    }
58453a5a1b3Sopenharmony_ci
58553a5a1b3Sopenharmony_ci  if (poll_again)
58653a5a1b3Sopenharmony_ci    select (0, &rfds, &wfds, &xfds, &tv);
58753a5a1b3Sopenharmony_ci
58853a5a1b3Sopenharmony_ci  /* Place a sentinel at the end of the array.  */
58953a5a1b3Sopenharmony_ci  handle_array[nhandles] = NULL;
59053a5a1b3Sopenharmony_ci  nhandles = 1;
59153a5a1b3Sopenharmony_ci  for (i = 0; i < nfd; i++)
59253a5a1b3Sopenharmony_ci    {
59353a5a1b3Sopenharmony_ci      int happened;
59453a5a1b3Sopenharmony_ci
59553a5a1b3Sopenharmony_ci      if (pfd[i].fd < 0)
59653a5a1b3Sopenharmony_ci        continue;
59753a5a1b3Sopenharmony_ci      if (!(pfd[i].events & (POLLIN | POLLRDNORM |
59853a5a1b3Sopenharmony_ci                             POLLOUT | POLLWRNORM | POLLWRBAND)))
59953a5a1b3Sopenharmony_ci        continue;
60053a5a1b3Sopenharmony_ci
60153a5a1b3Sopenharmony_ci      h = (HANDLE) HandleFromFd (pfd[i].fd);
60253a5a1b3Sopenharmony_ci      if (h != handle_array[nhandles])
60353a5a1b3Sopenharmony_ci        {
60453a5a1b3Sopenharmony_ci          /* It's a socket.  */
60553a5a1b3Sopenharmony_ci          WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
60653a5a1b3Sopenharmony_ci          WSAEventSelect ((SOCKET) h, 0, 0);
60753a5a1b3Sopenharmony_ci          /* Have to restore blocking as WSAEventSelect() clears it */
60853a5a1b3Sopenharmony_ci          if (!pa_is_fd_nonblock(pfd[i].fd))
60953a5a1b3Sopenharmony_ci            pa_make_fd_block(pfd[i].fd);
61053a5a1b3Sopenharmony_ci
61153a5a1b3Sopenharmony_ci          /* If we're lucky, WSAEnumNetworkEvents already provided a way
61253a5a1b3Sopenharmony_ci             to distinguish FD_READ and FD_ACCEPT; this saves a recv later.  */
61353a5a1b3Sopenharmony_ci          if (FD_ISSET ((SOCKET) h, &rfds)
61453a5a1b3Sopenharmony_ci              && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
61553a5a1b3Sopenharmony_ci            ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
61653a5a1b3Sopenharmony_ci          if (FD_ISSET ((SOCKET) h, &wfds))
61753a5a1b3Sopenharmony_ci            ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
61853a5a1b3Sopenharmony_ci          if (FD_ISSET ((SOCKET) h, &xfds))
61953a5a1b3Sopenharmony_ci            ev.lNetworkEvents |= FD_OOB;
62053a5a1b3Sopenharmony_ci
62153a5a1b3Sopenharmony_ci          happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events,
62253a5a1b3Sopenharmony_ci                                                     ev.lNetworkEvents);
62353a5a1b3Sopenharmony_ci        }
62453a5a1b3Sopenharmony_ci      else
62553a5a1b3Sopenharmony_ci        {
62653a5a1b3Sopenharmony_ci          /* Not a socket.  */
62753a5a1b3Sopenharmony_ci          int sought = pfd[i].events;
62853a5a1b3Sopenharmony_ci          happened = windows_compute_revents (h, &sought);
62953a5a1b3Sopenharmony_ci          nhandles++;
63053a5a1b3Sopenharmony_ci        }
63153a5a1b3Sopenharmony_ci
63253a5a1b3Sopenharmony_ci       if ((pfd[i].revents |= happened) != 0)
63353a5a1b3Sopenharmony_ci        rc++;
63453a5a1b3Sopenharmony_ci    }
63553a5a1b3Sopenharmony_ci
63653a5a1b3Sopenharmony_ci  if (!rc && timeout == INFTIM)
63753a5a1b3Sopenharmony_ci    {
63853a5a1b3Sopenharmony_ci      SleepEx (1, TRUE);
63953a5a1b3Sopenharmony_ci      goto restart;
64053a5a1b3Sopenharmony_ci    }
64153a5a1b3Sopenharmony_ci
64253a5a1b3Sopenharmony_ci  CloseHandle(hEvent);
64353a5a1b3Sopenharmony_ci
64453a5a1b3Sopenharmony_ci  return rc;
64553a5a1b3Sopenharmony_ci#endif
64653a5a1b3Sopenharmony_ci}
647