git
1/* Emulation for poll(2)
2Contributed by Paolo Bonzini.
3
4Copyright 2001-2003, 2006-2011 Free Software Foundation, Inc.
5
6This file is part of gnulib.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License along
19with this program; if not, see <http://www.gnu.org/licenses/>. */
20
21/* To bump the minimum Windows version to Windows Vista */
22#include "git-compat-util.h"23
24/* Tell gcc not to warn about the (nfd < 0) tests, below. */
25#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__26# pragma GCC diagnostic ignored "-Wtype-limits"27#endif28
29#if defined(WIN32)30# include <malloc.h>31#endif32
33#include <sys/types.h>34
35#include <errno.h>36#include <limits.h>37#include <assert.h>38
39#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__40# define WIN32_NATIVE41# if defined (_MSC_VER) && !defined(_WIN32_WINNT)42# define _WIN32_WINNT 0x050243# endif44# include <winsock2.h>45# include <windows.h>46# include <io.h>47# include <stdio.h>48# include <conio.h>49#else50# include <sys/time.h>51# include <sys/socket.h>52# ifndef NO_SYS_SELECT_H53# include <sys/select.h>54# endif55# include <unistd.h>56#endif57
58/* Specification. */
59#include "poll.h"60
61#ifdef HAVE_SYS_IOCTL_H62# include <sys/ioctl.h>63#endif64#ifdef HAVE_SYS_FILIO_H65# include <sys/filio.h>66#endif67
68#include <time.h>69
70#ifndef INFTIM71# define INFTIM (-1)72#endif73
74/* BeOS does not have MSG_PEEK. */
75#ifndef MSG_PEEK76# define MSG_PEEK 077#endif78
79#ifdef WIN32_NATIVE80
81#define IsConsoleHandle(h) (((long) (intptr_t) (h) & 3) == 3)82
83static BOOL84IsSocketHandle (HANDLE h)85{
86WSANETWORKEVENTS ev;87
88if (IsConsoleHandle (h))89return FALSE;90
91/* Under Wine, it seems that getsockopt returns 0 for pipes too.92WSAEnumNetworkEvents instead distinguishes the two correctly. */
93ev.lNetworkEvents = 0xDEADBEEF;94WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);95return ev.lNetworkEvents != 0xDEADBEEF;96}
97
98/* Declare data structures for ntdll functions. */
99typedef struct _FILE_PIPE_LOCAL_INFORMATION {100ULONG NamedPipeType;101ULONG NamedPipeConfiguration;102ULONG MaximumInstances;103ULONG CurrentInstances;104ULONG InboundQuota;105ULONG ReadDataAvailable;106ULONG OutboundQuota;107ULONG WriteQuotaAvailable;108ULONG NamedPipeState;109ULONG NamedPipeEnd;110} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;111
112typedef struct _IO_STATUS_BLOCK113{
114union {115DWORD Status;116PVOID Pointer;117} u;118ULONG_PTR Information;119} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;120
121typedef enum _FILE_INFORMATION_CLASS {122FilePipeLocalInformation = 24123} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;124
125typedef DWORD (WINAPI *PNtQueryInformationFile)126(HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);127
128# ifndef PIPE_BUF129# define PIPE_BUF 512130# endif131
132/* Compute revents values for file handle H. If some events cannot happen
133for the handle, eliminate them from *P_SOUGHT. */
134
135static int136win32_compute_revents (HANDLE h, int *p_sought)137{
138int i, ret, happened;139INPUT_RECORD *irbuffer;140DWORD avail, nbuffer;141BOOL bRet;142
143switch (GetFileType (h))144{145case FILE_TYPE_PIPE:146happened = 0;147if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)148{149if (avail)150happened |= *p_sought & (POLLIN | POLLRDNORM);151}152else if (GetLastError () == ERROR_BROKEN_PIPE)153happened |= POLLHUP;154
155else156{157/* It was the write-end of the pipe. Unfortunately there is no158reliable way of knowing if it can be written without blocking.
159Just say that it's all good. */
160happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);161}162return happened;163
164case FILE_TYPE_CHAR:165ret = WaitForSingleObject (h, 0);166if (!IsConsoleHandle (h))167return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;168
169nbuffer = avail = 0;170bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);171if (bRet)172{173/* Input buffer. */174*p_sought &= POLLIN | POLLRDNORM;175if (nbuffer == 0)176return POLLHUP;177if (!*p_sought)178return 0;179
180irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));181bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);182if (!bRet || avail == 0)183return POLLHUP;184
185for (i = 0; i < avail; i++)186if (irbuffer[i].EventType == KEY_EVENT)187return *p_sought;188return 0;189}190else191{192/* Screen buffer. */193*p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;194return *p_sought;195}196
197default:198ret = WaitForSingleObject (h, 0);199if (ret == WAIT_OBJECT_0)200return *p_sought & ~(POLLPRI | POLLRDBAND);201
202return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);203}204}
205
206/* Convert fd_sets returned by select into revents values. */
207
208static int209win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)210{
211int happened = 0;212
213if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)214happened |= (POLLIN | POLLRDNORM) & sought;215
216else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))217{218int r, error;219
220char data[64];221WSASetLastError (0);222r = recv (h, data, sizeof (data), MSG_PEEK);223error = WSAGetLastError ();224WSASetLastError (0);225
226if (r > 0 || error == WSAENOTCONN)227happened |= (POLLIN | POLLRDNORM) & sought;228
229/* Distinguish hung-up sockets from other errors. */230else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET231|| error == WSAECONNABORTED || error == WSAENETRESET)232happened |= POLLHUP;233
234else235happened |= POLLERR;236}237
238if (lNetworkEvents & (FD_WRITE | FD_CONNECT))239happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;240
241if (lNetworkEvents & FD_OOB)242happened |= (POLLPRI | POLLRDBAND) & sought;243
244return happened;245}
246
247#else /* !MinGW */248
249/* Convert select(2) returned fd_sets into poll(2) revents values. */
250static int251compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)252{
253int happened = 0;254if (FD_ISSET (fd, rfds))255{256int r;257int socket_errno;258
259# if defined __MACH__ && defined __APPLE__260/* There is a bug in Mac OS X that causes it to ignore MSG_PEEK261for some kinds of descriptors. Detect if this descriptor is a
262connected socket, a server socket, or something else using a
2630-byte recv, and use ioctl(2) to detect POLLHUP. */
264r = recv (fd, NULL, 0, MSG_PEEK);265socket_errno = (r < 0) ? errno : 0;266if (r == 0 || socket_errno == ENOTSOCK)267ioctl (fd, FIONREAD, &r);268# else269char data[64];270r = recv (fd, data, sizeof (data), MSG_PEEK);271socket_errno = (r < 0) ? errno : 0;272# endif273if (r == 0)274happened |= POLLHUP;275
276/* If the event happened on an unconnected server socket,277that's fine. */
278else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))279happened |= (POLLIN | POLLRDNORM) & sought;280
281/* Distinguish hung-up sockets from other errors. */282else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET283|| socket_errno == ECONNABORTED || socket_errno == ENETRESET)284happened |= POLLHUP;285
286/* some systems can't use recv() on non-socket, including HP NonStop */287else if (/* (r == -1) && */ socket_errno == ENOTSOCK)288happened |= (POLLIN | POLLRDNORM) & sought;289
290else291happened |= POLLERR;292}293
294if (FD_ISSET (fd, wfds))295happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;296
297if (FD_ISSET (fd, efds))298happened |= (POLLPRI | POLLRDBAND) & sought;299
300return happened;301}
302#endif /* !MinGW */303
304int
305poll (struct pollfd *pfd, nfds_t nfd, int timeout)306{
307#ifndef WIN32_NATIVE308fd_set rfds, wfds, efds;309struct timeval tv;310struct timeval *ptv;311int maxfd, rc;312nfds_t i;313
314# ifdef _SC_OPEN_MAX315static int sc_open_max = -1;316
317if (nfd < 0318|| (nfd > sc_open_max319&& (sc_open_max != -1320|| nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))321{322errno = EINVAL;323return -1;324}325# else /* !_SC_OPEN_MAX */326# ifdef OPEN_MAX327if (nfd < 0 || nfd > OPEN_MAX)328{329errno = EINVAL;330return -1;331}332# endif /* OPEN_MAX -- else, no check is needed */333# endif /* !_SC_OPEN_MAX */334
335/* EFAULT is not necessary to implement, but let's do it in the336simplest case. */
337if (!pfd && nfd)338{339errno = EFAULT;340return -1;341}342
343/* convert timeout number into a timeval structure */344if (timeout == 0)345{346ptv = &tv;347ptv->tv_sec = 0;348ptv->tv_usec = 0;349}350else if (timeout > 0)351{352ptv = &tv;353ptv->tv_sec = timeout / 1000;354ptv->tv_usec = (timeout % 1000) * 1000;355}356else if (timeout == INFTIM)357/* wait forever */358ptv = NULL;359else360{361errno = EINVAL;362return -1;363}364
365/* create fd sets and determine max fd */366maxfd = -1;367FD_ZERO (&rfds);368FD_ZERO (&wfds);369FD_ZERO (&efds);370for (i = 0; i < nfd; i++)371{372if (pfd[i].fd < 0)373continue;374
375if (pfd[i].events & (POLLIN | POLLRDNORM))376FD_SET (pfd[i].fd, &rfds);377
378/* see select(2): "the only exceptional condition detectable379is out-of-band data received on a socket", hence we push
380POLLWRBAND events onto wfds instead of efds. */
381if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))382FD_SET (pfd[i].fd, &wfds);383if (pfd[i].events & (POLLPRI | POLLRDBAND))384FD_SET (pfd[i].fd, &efds);385if (pfd[i].fd >= maxfd386&& (pfd[i].events & (POLLIN | POLLOUT | POLLPRI387| POLLRDNORM | POLLRDBAND388| POLLWRNORM | POLLWRBAND)))389{390maxfd = pfd[i].fd;391if (maxfd > FD_SETSIZE)392{393errno = EOVERFLOW;394return -1;395}396}397}398
399/* examine fd sets */400rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);401if (rc < 0)402return rc;403
404/* establish results */405rc = 0;406for (i = 0; i < nfd; i++)407if (pfd[i].fd < 0)408pfd[i].revents = 0;409else410{411int happened = compute_revents (pfd[i].fd, pfd[i].events,412&rfds, &wfds, &efds);413if (happened)414{415pfd[i].revents = happened;416rc++;417}418else419{420pfd[i].revents = 0;421}422}423
424return rc;425#else426static struct timeval tv0;427static HANDLE hEvent;428WSANETWORKEVENTS ev;429HANDLE h, handle_array[FD_SETSIZE + 2];430DWORD ret, wait_timeout, nhandles, orig_timeout = 0;431ULONGLONG start = 0;432fd_set rfds, wfds, xfds;433BOOL poll_again;434MSG msg;435int rc = 0;436nfds_t i;437
438if (nfd < 0 || timeout < -1)439{440errno = EINVAL;441return -1;442}443
444if (timeout != INFTIM)445{446orig_timeout = timeout;447start = GetTickCount64();448}449
450if (!hEvent)451hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);452
453restart:454handle_array[0] = hEvent;455nhandles = 1;456FD_ZERO (&rfds);457FD_ZERO (&wfds);458FD_ZERO (&xfds);459
460/* Classify socket handles and create fd sets. */461for (i = 0; i < nfd; i++)462{463int sought = pfd[i].events;464pfd[i].revents = 0;465if (pfd[i].fd < 0)466continue;467if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND468| POLLPRI | POLLRDBAND)))469continue;470
471h = (HANDLE) _get_osfhandle (pfd[i].fd);472assert (h != NULL);473if (IsSocketHandle (h))474{475int requested = FD_CLOSE;476
477/* see above; socket handles are mapped onto select. */478if (sought & (POLLIN | POLLRDNORM))479{480requested |= FD_READ | FD_ACCEPT;481FD_SET ((SOCKET) h, &rfds);482}483if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))484{485requested |= FD_WRITE | FD_CONNECT;486FD_SET ((SOCKET) h, &wfds);487}488if (sought & (POLLPRI | POLLRDBAND))489{490requested |= FD_OOB;491FD_SET ((SOCKET) h, &xfds);492}493
494if (requested)495WSAEventSelect ((SOCKET) h, hEvent, requested);496}497else498{499/* Poll now. If we get an event, do not poll again. Also,500screen buffer handles are waitable, and they'll block until
501a character is available. win32_compute_revents eliminates
502bits for the "wrong" direction. */
503pfd[i].revents = win32_compute_revents (h, &sought);504if (sought)505handle_array[nhandles++] = h;506if (pfd[i].revents)507timeout = 0;508}509}510
511if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)512{513/* Do MsgWaitForMultipleObjects anyway to dispatch messages, but514no need to call select again. */
515poll_again = FALSE;516wait_timeout = 0;517}518else519{520poll_again = TRUE;521if (timeout == INFTIM)522wait_timeout = INFINITE;523else524wait_timeout = timeout;525}526
527for (;;)528{529ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,530wait_timeout, QS_ALLINPUT);531
532if (ret == WAIT_OBJECT_0 + nhandles)533{534/* new input of some other kind */535BOOL bRet;536while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)537{538TranslateMessage (&msg);539DispatchMessage (&msg);540}541}542else543break;544}545
546if (poll_again)547select (0, &rfds, &wfds, &xfds, &tv0);548
549/* Place a sentinel at the end of the array. */550handle_array[nhandles] = NULL;551nhandles = 1;552for (i = 0; i < nfd; i++)553{554int happened;555
556if (pfd[i].fd < 0)557continue;558if (!(pfd[i].events & (POLLIN | POLLRDNORM |559POLLOUT | POLLWRNORM | POLLWRBAND)))560continue;561
562h = (HANDLE) _get_osfhandle (pfd[i].fd);563if (h != handle_array[nhandles])564{565/* It's a socket. */566WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);567WSAEventSelect ((SOCKET) h, NULL, 0);568
569/* If we're lucky, WSAEnumNetworkEvents already provided a way570to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
571if (FD_ISSET ((SOCKET) h, &rfds)572&& !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))573ev.lNetworkEvents |= FD_READ | FD_ACCEPT;574if (FD_ISSET ((SOCKET) h, &wfds))575ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;576if (FD_ISSET ((SOCKET) h, &xfds))577ev.lNetworkEvents |= FD_OOB;578
579happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,580ev.lNetworkEvents);581}582else583{584/* Not a socket. */585int sought = pfd[i].events;586happened = win32_compute_revents (h, &sought);587nhandles++;588}589
590if ((pfd[i].revents |= happened) != 0)591rc++;592}593
594if (!rc && orig_timeout && timeout != INFTIM)595{596ULONGLONG elapsed = GetTickCount64() - start;597timeout = elapsed >= orig_timeout ? 0 : (int)(orig_timeout - elapsed);598}599
600if (!rc && timeout)601{602SleepEx (1, TRUE);603goto restart;604}605
606return rc;607#endif608}
609