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