From 28a73ad1203efc6f6dc33629ce653f45081210fa Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 7 Dec 2009 00:40:03 +0100 Subject: hack around another OS X bug: recv() with MSG_PEEK does not work At least for pipes, recv() with MSG_PEEK does actually eat up data from file descriptors. Hence, this can't be used for PULLHUP emulation. Use another ioctl hack for that. --- src/pulsecore/poll.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c index 1dcace8b..b98fb169 100644 --- a/src/pulsecore/poll.c +++ b/src/pulsecore/poll.c @@ -35,6 +35,10 @@ #include #endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + #include #ifdef HAVE_SYS_SELECT_H @@ -60,7 +64,9 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { struct pollfd *f; int ready; int maxfd = 0; +#ifdef OS_IS_WIN32 char data[64]; +#endif FD_ZERO (&rset); FD_ZERO (&wset); @@ -103,6 +109,7 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); + if ((ready == -1) && (errno == EBADF)) { ready = 0; @@ -165,6 +172,8 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { #endif if (ready > 0) { + int r; + ready = 0; for (f = fds; f < &fds[nfds]; ++f) { f->revents = 0; @@ -172,6 +181,18 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { 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. */ + 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) { @@ -179,6 +200,7 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { f->revents |= POLLHUP; } } +#endif if (f->revents == 0) f->revents |= POLLIN; -- cgit