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