1 /* Emulation for poll(2)
2 Contributed by Paolo Bonzini.
4 Copyright 2001-2003, 2006-2011 Free Software Foundation, Inc.
6 This file is part of gnulib.
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)
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.
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. */
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"
31 #include <sys/types.h>
40 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
42 # if defined (_MSC_VER) && !defined(_WIN32_WINNT)
43 # define _WIN32_WINNT 0x0502
45 # include <winsock2.h>
51 # include <sys/time.h>
52 # include <sys/socket.h>
53 # ifndef NO_SYS_SELECT_H
54 # include <sys/select.h>
59 #ifdef HAVE_SYS_IOCTL_H
60 # include <sys/ioctl.h>
62 #ifdef HAVE_SYS_FILIO_H
63 # include <sys/filio.h>
72 /* BeOS does not have MSG_PEEK. */
79 #define IsConsoleHandle(h) (((long) (intptr_t) (h) & 3) == 3)
82 IsSocketHandle (HANDLE h
)
86 if (IsConsoleHandle (h
))
89 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
90 WSAEnumNetworkEvents instead distinguishes the two correctly. */
91 ev
.lNetworkEvents
= 0xDEADBEEF;
92 WSAEnumNetworkEvents ((SOCKET
) h
, NULL
, &ev
);
93 return ev
.lNetworkEvents
!= 0xDEADBEEF;
96 /* Declare data structures for ntdll functions. */
97 typedef struct _FILE_PIPE_LOCAL_INFORMATION
{
99 ULONG NamedPipeConfiguration
;
100 ULONG MaximumInstances
;
101 ULONG CurrentInstances
;
103 ULONG ReadDataAvailable
;
105 ULONG WriteQuotaAvailable
;
106 ULONG NamedPipeState
;
108 } FILE_PIPE_LOCAL_INFORMATION
, *PFILE_PIPE_LOCAL_INFORMATION
;
110 typedef struct _IO_STATUS_BLOCK
116 ULONG_PTR Information
;
117 } IO_STATUS_BLOCK
, *PIO_STATUS_BLOCK
;
119 typedef enum _FILE_INFORMATION_CLASS
{
120 FilePipeLocalInformation
= 24
121 } FILE_INFORMATION_CLASS
, *PFILE_INFORMATION_CLASS
;
123 typedef DWORD (WINAPI
*PNtQueryInformationFile
)
124 (HANDLE
, IO_STATUS_BLOCK
*, VOID
*, ULONG
, FILE_INFORMATION_CLASS
);
127 # define PIPE_BUF 512
130 /* Compute revents values for file handle H. If some events cannot happen
131 for the handle, eliminate them from *P_SOUGHT. */
134 win32_compute_revents (HANDLE h
, int *p_sought
)
136 int i
, ret
, happened
;
137 INPUT_RECORD
*irbuffer
;
138 DWORD avail
, nbuffer
;
140 IO_STATUS_BLOCK iosb
;
141 FILE_PIPE_LOCAL_INFORMATION fpli
;
142 static PNtQueryInformationFile NtQueryInformationFile
;
143 static BOOL once_only
;
145 switch (GetFileType (h
))
150 NtQueryInformationFile
= (PNtQueryInformationFile
)
151 GetProcAddress (GetModuleHandle ("ntdll.dll"),
152 "NtQueryInformationFile");
157 if (PeekNamedPipe (h
, NULL
, 0, NULL
, &avail
, NULL
) != 0)
160 happened
|= *p_sought
& (POLLIN
| POLLRDNORM
);
162 else if (GetLastError () == ERROR_BROKEN_PIPE
)
167 /* It was the write-end of the pipe. Check if it is writable.
168 If NtQueryInformationFile fails, optimistically assume the pipe is
169 writable. This could happen on Win9x, where NtQueryInformationFile
170 is not available, or if we inherit a pipe that doesn't permit
171 FILE_READ_ATTRIBUTES access on the write end (I think this should
172 not happen since WinXP SP2; WINE seems fine too). Otherwise,
173 ensure that enough space is available for atomic writes. */
174 memset (&iosb
, 0, sizeof (iosb
));
175 memset (&fpli
, 0, sizeof (fpli
));
177 if (!NtQueryInformationFile
178 || NtQueryInformationFile (h
, &iosb
, &fpli
, sizeof (fpli
),
179 FilePipeLocalInformation
)
180 || fpli
.WriteQuotaAvailable
>= PIPE_BUF
181 || (fpli
.OutboundQuota
< PIPE_BUF
&&
182 fpli
.WriteQuotaAvailable
== fpli
.OutboundQuota
))
183 happened
|= *p_sought
& (POLLOUT
| POLLWRNORM
| POLLWRBAND
);
188 ret
= WaitForSingleObject (h
, 0);
189 if (!IsConsoleHandle (h
))
190 return ret
== WAIT_OBJECT_0
? *p_sought
& ~(POLLPRI
| POLLRDBAND
) : 0;
193 bRet
= GetNumberOfConsoleInputEvents (h
, &nbuffer
);
197 *p_sought
&= POLLIN
| POLLRDNORM
;
203 irbuffer
= (INPUT_RECORD
*) alloca (nbuffer
* sizeof (INPUT_RECORD
));
204 bRet
= PeekConsoleInput (h
, irbuffer
, nbuffer
, &avail
);
205 if (!bRet
|| avail
== 0)
208 for (i
= 0; i
< avail
; i
++)
209 if (irbuffer
[i
].EventType
== KEY_EVENT
)
216 *p_sought
&= POLLOUT
| POLLWRNORM
| POLLWRBAND
;
221 ret
= WaitForSingleObject (h
, 0);
222 if (ret
== WAIT_OBJECT_0
)
223 return *p_sought
& ~(POLLPRI
| POLLRDBAND
);
225 return *p_sought
& (POLLOUT
| POLLWRNORM
| POLLWRBAND
);
229 /* Convert fd_sets returned by select into revents values. */
232 win32_compute_revents_socket (SOCKET h
, int sought
, long lNetworkEvents
)
236 if ((lNetworkEvents
& (FD_READ
| FD_ACCEPT
| FD_CLOSE
)) == FD_ACCEPT
)
237 happened
|= (POLLIN
| POLLRDNORM
) & sought
;
239 else if (lNetworkEvents
& (FD_READ
| FD_ACCEPT
| FD_CLOSE
))
245 r
= recv (h
, data
, sizeof (data
), MSG_PEEK
);
246 error
= WSAGetLastError ();
249 if (r
> 0 || error
== WSAENOTCONN
)
250 happened
|= (POLLIN
| POLLRDNORM
) & sought
;
252 /* Distinguish hung-up sockets from other errors. */
253 else if (r
== 0 || error
== WSAESHUTDOWN
|| error
== WSAECONNRESET
254 || error
== WSAECONNABORTED
|| error
== WSAENETRESET
)
261 if (lNetworkEvents
& (FD_WRITE
| FD_CONNECT
))
262 happened
|= (POLLOUT
| POLLWRNORM
| POLLWRBAND
) & sought
;
264 if (lNetworkEvents
& FD_OOB
)
265 happened
|= (POLLPRI
| POLLRDBAND
) & sought
;
272 /* Convert select(2) returned fd_sets into poll(2) revents values. */
274 compute_revents (int fd
, int sought
, fd_set
*rfds
, fd_set
*wfds
, fd_set
*efds
)
277 if (FD_ISSET (fd
, rfds
))
282 # if defined __MACH__ && defined __APPLE__
283 /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
284 for some kinds of descriptors. Detect if this descriptor is a
285 connected socket, a server socket, or something else using a
286 0-byte recv, and use ioctl(2) to detect POLLHUP. */
287 r
= recv (fd
, NULL
, 0, MSG_PEEK
);
288 socket_errno
= (r
< 0) ? errno
: 0;
289 if (r
== 0 || socket_errno
== ENOTSOCK
)
290 ioctl (fd
, FIONREAD
, &r
);
293 r
= recv (fd
, data
, sizeof (data
), MSG_PEEK
);
294 socket_errno
= (r
< 0) ? errno
: 0;
299 /* If the event happened on an unconnected server socket,
301 else if (r
> 0 || ( /* (r == -1) && */ socket_errno
== ENOTCONN
))
302 happened
|= (POLLIN
| POLLRDNORM
) & sought
;
304 /* Distinguish hung-up sockets from other errors. */
305 else if (socket_errno
== ESHUTDOWN
|| socket_errno
== ECONNRESET
306 || socket_errno
== ECONNABORTED
|| socket_errno
== ENETRESET
)
309 /* some systems can't use recv() on non-socket, including HP NonStop */
310 else if (/* (r == -1) && */ socket_errno
== ENOTSOCK
)
311 happened
|= (POLLIN
| POLLRDNORM
) & sought
;
317 if (FD_ISSET (fd
, wfds
))
318 happened
|= (POLLOUT
| POLLWRNORM
| POLLWRBAND
) & sought
;
320 if (FD_ISSET (fd
, efds
))
321 happened
|= (POLLPRI
| POLLRDBAND
) & sought
;
328 poll (struct pollfd
*pfd
, nfds_t nfd
, int timeout
)
331 fd_set rfds
, wfds
, efds
;
338 static int sc_open_max
= -1;
341 || (nfd
> sc_open_max
342 && (sc_open_max
!= -1
343 || nfd
> (sc_open_max
= sysconf (_SC_OPEN_MAX
)))))
348 # else /* !_SC_OPEN_MAX */
350 if (nfd
< 0 || nfd
> OPEN_MAX
)
355 # endif /* OPEN_MAX -- else, no check is needed */
356 # endif /* !_SC_OPEN_MAX */
358 /* EFAULT is not necessary to implement, but let's do it in the
366 /* convert timeout number into a timeval structure */
373 else if (timeout
> 0)
376 ptv
->tv_sec
= timeout
/ 1000;
377 ptv
->tv_usec
= (timeout
% 1000) * 1000;
379 else if (timeout
== INFTIM
)
388 /* create fd sets and determine max fd */
393 for (i
= 0; i
< nfd
; i
++)
398 if (pfd
[i
].events
& (POLLIN
| POLLRDNORM
))
399 FD_SET (pfd
[i
].fd
, &rfds
);
401 /* see select(2): "the only exceptional condition detectable
402 is out-of-band data received on a socket", hence we push
403 POLLWRBAND events onto wfds instead of efds. */
404 if (pfd
[i
].events
& (POLLOUT
| POLLWRNORM
| POLLWRBAND
))
405 FD_SET (pfd
[i
].fd
, &wfds
);
406 if (pfd
[i
].events
& (POLLPRI
| POLLRDBAND
))
407 FD_SET (pfd
[i
].fd
, &efds
);
408 if (pfd
[i
].fd
>= maxfd
409 && (pfd
[i
].events
& (POLLIN
| POLLOUT
| POLLPRI
410 | POLLRDNORM
| POLLRDBAND
411 | POLLWRNORM
| POLLWRBAND
)))
414 if (maxfd
> FD_SETSIZE
)
422 /* examine fd sets */
423 rc
= select (maxfd
+ 1, &rfds
, &wfds
, &efds
, ptv
);
427 /* establish results */
429 for (i
= 0; i
< nfd
; i
++)
434 int happened
= compute_revents (pfd
[i
].fd
, pfd
[i
].events
,
435 &rfds
, &wfds
, &efds
);
438 pfd
[i
].revents
= happened
;
445 static struct timeval tv0
;
446 static HANDLE hEvent
;
448 HANDLE h
, handle_array
[FD_SETSIZE
+ 2];
449 DWORD ret
, wait_timeout
, nhandles
, start
= 0, elapsed
, orig_timeout
= 0;
450 fd_set rfds
, wfds
, xfds
;
456 if (nfd
< 0 || timeout
< -1)
462 if (timeout
!= INFTIM
)
464 orig_timeout
= timeout
;
465 start
= GetTickCount();
469 hEvent
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
472 handle_array
[0] = hEvent
;
478 /* Classify socket handles and create fd sets. */
479 for (i
= 0; i
< nfd
; i
++)
481 int sought
= pfd
[i
].events
;
485 if (!(sought
& (POLLIN
| POLLRDNORM
| POLLOUT
| POLLWRNORM
| POLLWRBAND
486 | POLLPRI
| POLLRDBAND
)))
489 h
= (HANDLE
) _get_osfhandle (pfd
[i
].fd
);
491 if (IsSocketHandle (h
))
493 int requested
= FD_CLOSE
;
495 /* see above; socket handles are mapped onto select. */
496 if (sought
& (POLLIN
| POLLRDNORM
))
498 requested
|= FD_READ
| FD_ACCEPT
;
499 FD_SET ((SOCKET
) h
, &rfds
);
501 if (sought
& (POLLOUT
| POLLWRNORM
| POLLWRBAND
))
503 requested
|= FD_WRITE
| FD_CONNECT
;
504 FD_SET ((SOCKET
) h
, &wfds
);
506 if (sought
& (POLLPRI
| POLLRDBAND
))
509 FD_SET ((SOCKET
) h
, &xfds
);
513 WSAEventSelect ((SOCKET
) h
, hEvent
, requested
);
517 /* Poll now. If we get an event, do not poll again. Also,
518 screen buffer handles are waitable, and they'll block until
519 a character is available. win32_compute_revents eliminates
520 bits for the "wrong" direction. */
521 pfd
[i
].revents
= win32_compute_revents (h
, &sought
);
523 handle_array
[nhandles
++] = h
;
529 if (select (0, &rfds
, &wfds
, &xfds
, &tv0
) > 0)
531 /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
532 no need to call select again. */
539 if (timeout
== INFTIM
)
540 wait_timeout
= INFINITE
;
542 wait_timeout
= timeout
;
547 ret
= MsgWaitForMultipleObjects (nhandles
, handle_array
, FALSE
,
548 wait_timeout
, QS_ALLINPUT
);
550 if (ret
== WAIT_OBJECT_0
+ nhandles
)
552 /* new input of some other kind */
554 while ((bRet
= PeekMessage (&msg
, NULL
, 0, 0, PM_REMOVE
)) != 0)
556 TranslateMessage (&msg
);
557 DispatchMessage (&msg
);
565 select (0, &rfds
, &wfds
, &xfds
, &tv0
);
567 /* Place a sentinel at the end of the array. */
568 handle_array
[nhandles
] = NULL
;
570 for (i
= 0; i
< nfd
; i
++)
576 if (!(pfd
[i
].events
& (POLLIN
| POLLRDNORM
|
577 POLLOUT
| POLLWRNORM
| POLLWRBAND
)))
580 h
= (HANDLE
) _get_osfhandle (pfd
[i
].fd
);
581 if (h
!= handle_array
[nhandles
])
584 WSAEnumNetworkEvents ((SOCKET
) h
, NULL
, &ev
);
585 WSAEventSelect ((SOCKET
) h
, NULL
, 0);
587 /* If we're lucky, WSAEnumNetworkEvents already provided a way
588 to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
589 if (FD_ISSET ((SOCKET
) h
, &rfds
)
590 && !(ev
.lNetworkEvents
& (FD_READ
| FD_ACCEPT
)))
591 ev
.lNetworkEvents
|= FD_READ
| FD_ACCEPT
;
592 if (FD_ISSET ((SOCKET
) h
, &wfds
))
593 ev
.lNetworkEvents
|= FD_WRITE
| FD_CONNECT
;
594 if (FD_ISSET ((SOCKET
) h
, &xfds
))
595 ev
.lNetworkEvents
|= FD_OOB
;
597 happened
= win32_compute_revents_socket ((SOCKET
) h
, pfd
[i
].events
,
603 int sought
= pfd
[i
].events
;
604 happened
= win32_compute_revents (h
, &sought
);
608 if ((pfd
[i
].revents
|= happened
) != 0)
612 if (!rc
&& orig_timeout
&& timeout
!= INFTIM
)
614 elapsed
= GetTickCount() - start
;
615 timeout
= elapsed
>= orig_timeout
? 0 : orig_timeout
- elapsed
;