summaryrefslogtreecommitdiffstats
path: root/src/pulsecore/poll-posix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulsecore/poll-posix.c')
-rw-r--r--src/pulsecore/poll-posix.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/src/pulsecore/poll-posix.c b/src/pulsecore/poll-posix.c
new file mode 100644
index 0000000..e232295
--- /dev/null
+++ b/src/pulsecore/poll-posix.c
@@ -0,0 +1,235 @@
+
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
+***/
+
+/***
+ Based on work for the GNU C Library.
+ Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
+***/
+
+/* Poll the file descriptors described by the NFDS structures starting at
+ FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
+ an event to occur; if TIMEOUT is -1, block until an event occurs.
+ Returns the number of file descriptors with events, zero if timed out,
+ or -1 for errors. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include <pulsecore/socket.h>
+#include <pulsecore/core-util.h>
+#include <pulse/util.h>
+
+#include "poll.h"
+
+/* Mac OSX fails to implement poll() in a working way since 10.4. IOW, for
+ * several years. We need to enable a dirty workaround and emulate that call
+ * with select(), just like for Windows. sic! */
+
+#if !defined(HAVE_POLL_H) || defined(OS_IS_DARWIN)
+
+int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
+ struct timeval tv;
+ fd_set rset, wset, xset;
+ struct pollfd *f;
+ int ready;
+ int maxfd = 0;
+#ifdef OS_IS_WIN32
+ char data[64];
+#endif
+
+ FD_ZERO (&rset);
+ FD_ZERO (&wset);
+ FD_ZERO (&xset);
+
+ if (nfds == 0) {
+ if (timeout >= 0) {
+ pa_msleep(timeout);
+ return 0;
+ }
+
+#ifdef OS_IS_WIN32
+ /*
+ * Windows does not support signals properly so waiting for them would
+ * mean a deadlock.
+ */
+ pa_msleep(100);
+ return 0;
+#else
+ return select(0, NULL, NULL, NULL, NULL);
+#endif
+ }
+
+ for (f = fds; f < &fds[nfds]; ++f) {
+ if (f->fd != -1) {
+ if (f->events & POLLIN)
+ FD_SET (f->fd, &rset);
+ if (f->events & POLLOUT)
+ FD_SET (f->fd, &wset);
+ if (f->events & POLLPRI)
+ FD_SET (f->fd, &xset);
+ if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
+ maxfd = f->fd;
+ }
+ }
+
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+
+ ready = select(maxfd + 1, &rset, &wset, &xset, (timeout == -1 ? NULL : &tv));
+
+ if ((ready == -1) && (errno == EBADF)) {
+ ready = 0;
+ maxfd = -1;
+
+#ifdef OS_IS_WIN32
+ /*
+ * Windows has no fcntl(), so we have to trick around with more
+ * select() calls to find out what went wrong
+ */
+
+ FD_ZERO (&rset);
+ FD_ZERO (&wset);
+ FD_ZERO (&xset);
+
+ for (f = fds; f < &fds[nfds]; ++f) {
+ if (f->fd != -1) {
+ fd_set sngl_rset, sngl_wset, sngl_xset;
+
+ FD_ZERO (&sngl_rset);
+ FD_ZERO (&sngl_wset);
+ FD_ZERO (&sngl_xset);
+
+ if (f->events & POLLIN)
+ FD_SET (f->fd, &sngl_rset);
+ if (f->events & POLLOUT)
+ FD_SET (f->fd, &sngl_wset);
+ if (f->events & POLLPRI)
+ FD_SET (f->fd, &sngl_xset);
+ if (f->events & (POLLIN|POLLOUT|POLLPRI)) {
+ struct timeval singl_tv;
+
+ singl_tv.tv_sec = 0;
+ singl_tv.tv_usec = 0;
+
+ if (select(f->fd, &rset, &wset, &xset, &singl_tv) != -1) {
+ if (f->events & POLLIN)
+ FD_SET (f->fd, &rset);
+ if (f->events & POLLOUT)
+ FD_SET (f->fd, &wset);
+ if (f->events & POLLPRI)
+ FD_SET (f->fd, &xset);
+ if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
+ maxfd = f->fd;
+ ++ready;
+ } else if (errno == EBADF)
+ f->revents |= POLLNVAL;
+ }
+ }
+ }
+
+#else /* !OS_IS_WIN32 */
+
+ for (f = fds; f < &fds[nfds]; f++)
+ if (f->fd != -1) {
+ /* use fcntl() to find out whether the descriptor is valid */
+ if (fcntl(f->fd, F_GETFL) != -1) {
+ if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) {
+ maxfd = f->fd;
+ ready++;
+ }
+ } else {
+ FD_CLR(f->fd, &rset);
+ FD_CLR(f->fd, &wset);
+ FD_CLR(f->fd, &xset);
+ }
+ }
+
+#endif
+
+ if (ready) {
+ /* Linux alters the tv struct... but it shouldn't matter here ...
+ * as we're going to be a little bit out anyway as we've just eaten
+ * more than a couple of cpu cycles above */
+ ready = select(maxfd + 1, &rset, &wset, &xset, (timeout == -1 ? NULL : &tv));
+ }
+ }
+
+#ifdef OS_IS_WIN32
+ errno = WSAGetLastError();
+#endif
+
+ if (ready > 0) {
+ ready = 0;
+ for (f = fds; f < &fds[nfds]; ++f) {
+ f->revents = 0;
+ if (f->fd != -1) {
+ if (FD_ISSET (f->fd, &rset)) {
+ /* support for POLLHUP. An hung up descriptor does not
+ increase the return value! */
+#ifdef OS_IS_DARWIN
+ /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
+ * for some kinds of descriptors. Detect if this descriptor is a
+ * connected socket, a server socket, or something else using a
+ * 0-byte recv, and use ioctl(2) to detect POLLHUP. */
+ int r = recv(f->fd, NULL, 0, MSG_PEEK);
+ if (r == 0 || (r < 0 && errno == ENOTSOCK))
+ ioctl(f->fd, FIONREAD, &r);
+
+ if (r == 0)
+ f->revents |= POLLHUP;
+#else /* !OS_IS_DARWIN */
+ if (recv (f->fd, data, 64, MSG_PEEK) == -1) {
+ if (errno == ESHUTDOWN || errno == ECONNRESET ||
+ errno == ECONNABORTED || errno == ENETRESET) {
+ fprintf(stderr, "Hangup\n");
+ f->revents |= POLLHUP;
+ }
+ }
+#endif
+
+ if (f->revents == 0)
+ f->revents |= POLLIN;
+ }
+ if (FD_ISSET (f->fd, &wset))
+ f->revents |= POLLOUT;
+ if (FD_ISSET (f->fd, &xset))
+ f->revents |= POLLPRI;
+ }
+ if (f->revents)
+ ready++;
+ }
+ }
+
+ return ready;
+}
+
+#endif /* HAVE_SYS_POLL_H */