[pulseaudio-commits] 2 commits - src/Makefile.am src/pulse src/pulsecore

Arun Raghavan arun at kemper.freedesktop.org
Tue Oct 30 05:25:20 PDT 2012


 src/Makefile.am            |    7 
 src/pulse/mainloop.c       |   18 -
 src/pulsecore/core-util.c  |    5 
 src/pulsecore/poll-posix.c |  237 ++++++++++++++++
 src/pulsecore/poll-win32.c |  639 +++++++++++++++++++++++++++++++++++++++++++++
 src/pulsecore/poll.c       |  237 ----------------
 6 files changed, 885 insertions(+), 258 deletions(-)

New commits:
commit a8e7d8bc2c97be1d99546d8229b84f407b6f2d26
Author: Thomas Martitz <kugel at rockbox.org>
Date:   Tue Oct 30 11:35:26 2012 +0100

    core-util: Don't error out on existing runtime directory.
    
    When compiling without HAVE_SYMLINK the runtime dir is a real directory,
    which is attempted to be created. In the case it already exists we shouldn't
    error out. The HAVE_SYMLINK-enabled code already does this.

diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index f171164..d349bab 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -1789,8 +1789,9 @@ char *pa_get_runtime_dir(void) {
                 goto fail;
             }
 #else
-            /* No symlink possible, so let's just create the runtime directly */
-            if (mkdir(k) < 0)
+            /* No symlink possible, so let's just create the runtime directly
+             * Do not check again if it exists since it cannot be a symlink */
+            if (mkdir(k) < 0 && errno != EEXIST)
                 goto fail;
 #endif
 

commit 7e344b5ff04512b7323d6c42a7bcbe5438ea4e3f
Author: Thomas Martitz <kuge at rockbox.org>
Date:   Tue Oct 30 11:35:24 2012 +0100

    core: Proper poll() emulation to fix pacat and friends on Windows
    
    Currently, Windows versions of pacat and friends fail because the current
    poll emulation is not sufficient (it only works for socket fds).
    
    Luckily Gnulib has a much better emulation that seems to work good enough.
    The implementation has been largely copied (except a few bug fix
    regarding timeout handling, to be pushed upstream) and works on pipes
    and files as well. The copy has been obtained through their gnulib-tool utility,
    which gives a LGPLv2.1+ licensed file.
    
    This fixes the "Assertion (!e->dead) failed" error coming and lets pacat
    and friends stream happily to/from a server (I didn't actually test parec).

diff --git a/src/Makefile.am b/src/Makefile.am
index 88054cb..ed6f8e2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -604,7 +604,6 @@ libpulsecommon_ at PA_MAJORMINOR@_la_SOURCES = \
 		pulsecore/pdispatch.c pulsecore/pdispatch.h \
 		pulsecore/pid.c pulsecore/pid.h \
 		pulsecore/pipe.c pulsecore/pipe.h \
-		pulsecore/poll.c pulsecore/poll.h \
 		pulsecore/memtrap.c pulsecore/memtrap.h \
 		pulsecore/aupdate.c pulsecore/aupdate.h \
 		pulsecore/proplist-util.c pulsecore/proplist-util.h \
@@ -627,6 +626,12 @@ libpulsecommon_ at PA_MAJORMINOR@_la_SOURCES = \
 		pulsecore/sndfile-util.c pulsecore/sndfile-util.h \
 		pulsecore/socket.h
 
+if OS_IS_WIN32
+libpulsecommon_ at PA_MAJORMINOR@_la_SOURCES += pulsecore/poll-win32.c pulsecore/poll.h
+else
+libpulsecommon_ at PA_MAJORMINOR@_la_SOURCES += pulsecore/poll-posix.c pulsecore/poll.h
+endif
+
 libpulsecommon_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
 libpulsecommon_ at PA_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libpulsecommon_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LIBWRAP_LIBS) $(WINSOCK_LIBS) $(LTLIBICONV) $(LIBSNDFILE_LIBS)
diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c
index 5c0345e..725bdb4 100644
--- a/src/pulse/mainloop.c
+++ b/src/pulse/mainloop.c
@@ -175,24 +175,6 @@ static pa_io_event* mainloop_io_new(
     e->callback = callback;
     e->userdata = userdata;
 
-#ifdef OS_IS_WIN32
-    {
-        fd_set xset;
-        struct timeval tv;
-
-        tv.tv_sec = 0;
-        tv.tv_usec = 0;
-
-        FD_ZERO (&xset);
-        FD_SET (fd, &xset);
-
-        if ((select(fd, NULL, NULL, &xset, &tv) == -1) && (WSAGetLastError() == WSAENOTSOCK)) {
-            pa_log_warn("Cannot monitor non-socket file descriptors.");
-            e->dead = TRUE;
-        }
-    }
-#endif
-
     PA_LLIST_PREPEND(pa_io_event, m->io_events, e);
     m->rebuild_pollfds = TRUE;
     m->n_io_events ++;
diff --git a/src/pulsecore/poll-posix.c b/src/pulsecore/poll-posix.c
new file mode 100644
index 0000000..cd888b5
--- /dev/null
+++ b/src/pulsecore/poll-posix.c
@@ -0,0 +1,237 @@
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2006 Pierre Ossman <ossman at 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, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+/***
+   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 */
diff --git a/src/pulsecore/poll-win32.c b/src/pulsecore/poll-win32.c
new file mode 100644
index 0000000..4256ed7
--- /dev/null
+++ b/src/pulsecore/poll-win32.c
@@ -0,0 +1,639 @@
+
+/* Emulation for poll(2)
+   Contributed by Paolo Bonzini.
+
+   Copyright 2001-2003, 2006-2012 Free Software Foundation, Inc.
+
+   This file is part of gnulib.
+
+   This program 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, or (at your option)
+   any later version.
+
+   This program 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License along
+   with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+/* Tell gcc not to warn about the (nfd < 0) tests, below.  */
+#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
+# pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <malloc.h>
+
+#include <sys/types.h>
+
+/* Specification.  */
+#include "poll.h"
+typedef unsigned long nfds_t;
+
+#include <errno.h>
+#include <limits.h>
+#include <assert.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WINDOWS_NATIVE
+# include <winsock2.h>
+# include <windows.h>
+# include <io.h>
+# include <stdio.h>
+# include <conio.h>
+# if 0
+# include "msvc-nothrow.h"
+# endif
+#else
+# include <sys/time.h>
+# include <sys/socket.h>
+# include <sys/select.h>
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#include <time.h>
+
+#ifndef INFTIM
+# define INFTIM (-1)
+#endif
+
+/* BeOS does not have MSG_PEEK.  */
+#ifndef MSG_PEEK
+# define MSG_PEEK 0
+#endif
+
+#ifndef POLLRDNORM
+# define POLLRDNORM  0
+# define POLLRDBAND  0
+# define POLLWRNORM  0
+# define POLLWRBAND  0
+#endif
+
+#ifdef WINDOWS_NATIVE
+
+/* Optimized test whether a HANDLE refers to a console.
+   See <http://lists.gnu.org/archive/html/bug-gnulib/2009-08/msg00065.html>.  */
+#define IsConsoleHandle(h) (((intptr_t) (h) & 3) == 3)
+
+static BOOL
+IsSocketHandle (HANDLE h)
+{
+  WSANETWORKEVENTS ev;
+
+  if (IsConsoleHandle (h))
+    return FALSE;
+
+  /* Under Wine, it seems that getsockopt returns 0 for pipes too.
+     WSAEnumNetworkEvents instead distinguishes the two correctly.  */
+  ev.lNetworkEvents = 0xDEADBEEFl;
+  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+  return ev.lNetworkEvents != 0xDEADBEEFl;
+}
+
+static HANDLE
+HandleFromFd (int fd)
+{
+  /* since socket() returns a HANDLE already, try that first */
+  if (IsSocketHandle((HANDLE) fd))
+    return ((HANDLE) fd);
+
+  return ((HANDLE) _get_osfhandle(fd));
+}
+
+/* Declare data structures for ntdll functions.  */
+typedef struct _FILE_PIPE_LOCAL_INFORMATION {
+  ULONG NamedPipeType;
+  ULONG NamedPipeConfiguration;
+  ULONG MaximumInstances;
+  ULONG CurrentInstances;
+  ULONG InboundQuota;
+  ULONG ReadDataAvailable;
+  ULONG OutboundQuota;
+  ULONG WriteQuotaAvailable;
+  ULONG NamedPipeState;
+  ULONG NamedPipeEnd;
+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
+
+typedef struct _IO_STATUS_BLOCK
+{
+  union {
+    DWORD Status;
+    PVOID Pointer;
+  } u;
+  ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef enum _FILE_INFORMATION_CLASS {
+  FilePipeLocalInformation = 24
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef DWORD (WINAPI *PNtQueryInformationFile)
+         (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
+
+# ifndef PIPE_BUF
+#  define PIPE_BUF      512
+# endif
+
+/* Compute revents values for file handle H.  If some events cannot happen
+   for the handle, eliminate them from *P_SOUGHT.  */
+
+static int
+windows_compute_revents (HANDLE h, int *p_sought)
+{
+  int i, ret, happened;
+  INPUT_RECORD *irbuffer;
+  DWORD avail, nbuffer;
+  BOOL bRet;
+  IO_STATUS_BLOCK iosb;
+  FILE_PIPE_LOCAL_INFORMATION fpli;
+  static PNtQueryInformationFile NtQueryInformationFile;
+  static BOOL once_only;
+
+  switch (GetFileType (h))
+    {
+    case FILE_TYPE_PIPE:
+      if (!once_only)
+        {
+          NtQueryInformationFile = (PNtQueryInformationFile)
+            GetProcAddress (GetModuleHandle ("ntdll.dll"),
+                            "NtQueryInformationFile");
+          once_only = TRUE;
+        }
+
+      happened = 0;
+      if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
+        {
+          if (avail)
+            happened |= *p_sought & (POLLIN | POLLRDNORM);
+        }
+      else if (GetLastError () == ERROR_BROKEN_PIPE)
+        happened |= POLLHUP;
+
+      else
+        {
+          /* It was the write-end of the pipe.  Check if it is writable.
+             If NtQueryInformationFile fails, optimistically assume the pipe is
+             writable.  This could happen on Windows 9x, where
+             NtQueryInformationFile is not available, or if we inherit a pipe
+             that doesn't permit FILE_READ_ATTRIBUTES access on the write end
+             (I think this should not happen since Windows XP SP2; WINE seems
+             fine too).  Otherwise, ensure that enough space is available for
+             atomic writes.  */
+          memset (&iosb, 0, sizeof (iosb));
+          memset (&fpli, 0, sizeof (fpli));
+
+          if (!NtQueryInformationFile
+              || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
+                                         FilePipeLocalInformation)
+              || fpli.WriteQuotaAvailable >= PIPE_BUF
+              || (fpli.OutboundQuota < PIPE_BUF &&
+                  fpli.WriteQuotaAvailable == fpli.OutboundQuota))
+            happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+        }
+      return happened;
+
+    case FILE_TYPE_CHAR:
+      ret = WaitForSingleObject (h, 0);
+      if (!IsConsoleHandle (h))
+        return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
+
+      nbuffer = avail = 0;
+      bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
+      if (bRet)
+        {
+          /* Input buffer.  */
+          *p_sought &= POLLIN | POLLRDNORM;
+          if (nbuffer == 0)
+            return POLLHUP;
+          if (!*p_sought)
+            return 0;
+
+          irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
+          bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
+          if (!bRet || avail == 0)
+            return POLLHUP;
+
+          for (i = 0; i < avail; i++)
+            if (irbuffer[i].EventType == KEY_EVENT)
+              return *p_sought;
+          return 0;
+        }
+      else
+        {
+          /* Screen buffer.  */
+          *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
+          return *p_sought;
+        }
+
+    default:
+      ret = WaitForSingleObject (h, 0);
+      if (ret == WAIT_OBJECT_0)
+        return *p_sought & ~(POLLPRI | POLLRDBAND);
+
+      return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+    }
+}
+
+/* Convert fd_sets returned by select into revents values.  */
+
+static int
+windows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
+{
+  int happened = 0;
+
+  if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
+    happened |= (POLLIN | POLLRDNORM) & sought;
+
+  else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
+    {
+      int r, error;
+
+      char data[64];
+      WSASetLastError (0);
+      r = recv (h, data, sizeof (data), MSG_PEEK);
+      error = WSAGetLastError ();
+      WSASetLastError (0);
+
+      if (r > 0 || error == WSAENOTCONN)
+        happened |= (POLLIN | POLLRDNORM) & sought;
+
+      /* Distinguish hung-up sockets from other errors.  */
+      else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
+               || error == WSAECONNABORTED || error == WSAENETRESET)
+        happened |= POLLHUP;
+
+      else
+        happened |= POLLERR;
+    }
+
+  if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
+    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+  if (lNetworkEvents & FD_OOB)
+    happened |= (POLLPRI | POLLRDBAND) & sought;
+
+  return happened;
+}
+
+#else /* !MinGW */
+
+/* Convert select(2) returned fd_sets into poll(2) revents values.  */
+static int
+compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
+{
+  int happened = 0;
+  if (FD_ISSET (fd, rfds))
+    {
+      int r;
+      int socket_errno;
+
+# if defined __MACH__ && defined __APPLE__
+      /* 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 (fd, NULL, 0, MSG_PEEK);
+      socket_errno = (r < 0) ? errno : 0;
+      if (r == 0 || socket_errno == ENOTSOCK)
+        ioctl (fd, FIONREAD, &r);
+# else
+      char data[64];
+      r = recv (fd, data, sizeof (data), MSG_PEEK);
+      socket_errno = (r < 0) ? errno : 0;
+# endif
+      if (r == 0)
+        happened |= POLLHUP;
+
+      /* If the event happened on an unconnected server socket,
+         that's fine. */
+      else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
+        happened |= (POLLIN | POLLRDNORM) & sought;
+
+      /* Distinguish hung-up sockets from other errors.  */
+      else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
+               || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
+        happened |= POLLHUP;
+
+      /* some systems can't use recv() on non-socket, including HP NonStop */
+      else if (socket_errno == ENOTSOCK)
+        happened |= (POLLIN | POLLRDNORM) & sought;
+
+      else
+        happened |= POLLERR;
+    }
+
+  if (FD_ISSET (fd, wfds))
+    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+  if (FD_ISSET (fd, efds))
+    happened |= (POLLPRI | POLLRDBAND) & sought;
+
+  return happened;
+}
+#endif /* !MinGW */
+
+int
+pa_poll (struct pollfd *pfd, nfds_t nfd, int timeout)
+{
+  struct timeval tv;
+  struct timeval *ptv;
+#ifndef WINDOWS_NATIVE
+  fd_set rfds, wfds, efds;
+  int maxfd, rc;
+  nfds_t i;
+
+# ifdef _SC_OPEN_MAX
+  static int sc_open_max = -1;
+
+  if (nfd < 0
+      || (nfd > sc_open_max
+          && (sc_open_max != -1
+              || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+# else /* !_SC_OPEN_MAX */
+#  ifdef OPEN_MAX
+  if (nfd < 0 || nfd > OPEN_MAX)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+#  endif /* OPEN_MAX -- else, no check is needed */
+# endif /* !_SC_OPEN_MAX */
+#else /* WINDOWS_NATIVE*/
+  static HANDLE hEvent;
+  WSANETWORKEVENTS ev;
+  HANDLE h, handle_array[FD_SETSIZE + 2];
+  DWORD ret, wait_timeout, nhandles;
+  fd_set rfds, wfds, xfds;
+  BOOL poll_again;
+  MSG msg;
+  int rc = 0;
+  nfds_t i;
+#endif
+
+  /* EFAULT is not necessary to implement, but let's do it in the
+     simplest case. */
+  if (!pfd && nfd)
+    {
+      errno = EFAULT;
+      return -1;
+    }
+
+  /* convert timeout number into a timeval structure */
+  if (timeout == 0)
+    {
+      ptv = &tv;
+      ptv->tv_sec = 0;
+      ptv->tv_usec = 0;
+    }
+  else if (timeout > 0)
+    {
+      ptv = &tv;
+      ptv->tv_sec = timeout / 1000;
+      ptv->tv_usec = (timeout % 1000) * 1000;
+    }
+  else if (timeout == INFTIM)
+    /* wait forever */
+    ptv = NULL;
+  else
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+#ifndef WINDOWS_NATIVE
+  /* create fd sets and determine max fd */
+  maxfd = -1;
+  FD_ZERO (&rfds);
+  FD_ZERO (&wfds);
+  FD_ZERO (&efds);
+  for (i = 0; i < nfd; i++)
+    {
+      if (pfd[i].fd < 0)
+        continue;
+
+      if (pfd[i].events & (POLLIN | POLLRDNORM))
+        FD_SET (pfd[i].fd, &rfds);
+
+      /* see select(2): "the only exceptional condition detectable
+         is out-of-band data received on a socket", hence we push
+         POLLWRBAND events onto wfds instead of efds. */
+      if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
+        FD_SET (pfd[i].fd, &wfds);
+      if (pfd[i].events & (POLLPRI | POLLRDBAND))
+        FD_SET (pfd[i].fd, &efds);
+      if (pfd[i].fd >= maxfd
+          && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
+                               | POLLRDNORM | POLLRDBAND
+                               | POLLWRNORM | POLLWRBAND)))
+        {
+          maxfd = pfd[i].fd;
+          if (maxfd > FD_SETSIZE)
+            {
+              errno = EOVERFLOW;
+              return -1;
+            }
+        }
+    }
+
+  /* examine fd sets */
+  rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
+  if (rc < 0)
+    return rc;
+
+  /* establish results */
+  rc = 0;
+  for (i = 0; i < nfd; i++)
+    if (pfd[i].fd < 0)
+      pfd[i].revents = 0;
+    else
+      {
+        int happened = compute_revents (pfd[i].fd, pfd[i].events,
+                                        &rfds, &wfds, &efds);
+        if (happened)
+          {
+            pfd[i].revents = happened;
+            rc++;
+          }
+      }
+
+  return rc;
+#else
+
+  if (!hEvent)
+    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+
+restart:
+  handle_array[0] = hEvent;
+  nhandles = 1;
+  FD_ZERO (&rfds);
+  FD_ZERO (&wfds);
+  FD_ZERO (&xfds);
+
+  /* Classify socket handles and create fd sets. */
+  for (i = 0; i < nfd; i++)
+    {
+      int sought = pfd[i].events;
+      pfd[i].revents = 0;
+      if (pfd[i].fd < 0)
+        continue;
+      if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
+                      | POLLPRI | POLLRDBAND)))
+        continue;
+
+      h = HandleFromFd (pfd[i].fd);
+      assert (h != NULL && h != INVALID_HANDLE_VALUE);
+      if (IsSocketHandle (h))
+        {
+          int requested = FD_CLOSE;
+
+          /* see above; socket handles are mapped onto select.  */
+          if (sought & (POLLIN | POLLRDNORM))
+            {
+              requested |= FD_READ | FD_ACCEPT;
+              FD_SET ((SOCKET) h, &rfds);
+            }
+          if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
+            {
+              requested |= FD_WRITE | FD_CONNECT;
+              FD_SET ((SOCKET) h, &wfds);
+            }
+          if (sought & (POLLPRI | POLLRDBAND))
+            {
+              requested |= FD_OOB;
+              FD_SET ((SOCKET) h, &xfds);
+            }
+
+          if (requested)
+            WSAEventSelect ((SOCKET) h, hEvent, requested);
+        }
+      else
+        {
+          /* Poll now.  If we get an event, do not poll again.  Also,
+             screen buffer handles are waitable, and they'll block until
+             a character is available.  windows_compute_revents eliminates
+             bits for the "wrong" direction. */
+          pfd[i].revents = windows_compute_revents (h, &sought);
+          if (sought)
+            handle_array[nhandles++] = h;
+          if (pfd[i].revents)
+            timeout = 0;
+          else
+            {
+              if (!ptv)
+                ptv = &tv;
+              /* tune down to 0.25s. But don't touch smaller timeouts */
+              if (ptv->tv_usec > 250*1000 || ptv->tv_sec > 0)
+                ptv->tv_usec = 250*1000;
+              ptv->tv_sec = 0;
+            }
+        }
+    }
+
+  if (select (0, &rfds, &wfds, &xfds, ptv) > 0)
+    {
+      /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
+         no need to call select again.  */
+      poll_again = FALSE;
+      wait_timeout = 0;
+    }
+  else
+    {
+      poll_again = TRUE;
+      if (timeout == INFTIM)
+        wait_timeout = INFINITE;
+      else
+        wait_timeout = timeout;
+    }
+
+  for (;;)
+    {
+      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
+                                       wait_timeout, QS_ALLINPUT);
+
+      if (ret == WAIT_OBJECT_0 + nhandles)
+        {
+          /* new input of some other kind */
+          BOOL bRet;
+          while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
+            {
+              TranslateMessage (&msg);
+              DispatchMessage (&msg);
+            }
+        }
+      else
+        break;
+    }
+
+  if (poll_again)
+    select (0, &rfds, &wfds, &xfds, ptv);
+
+  /* Place a sentinel at the end of the array.  */
+  handle_array[nhandles] = NULL;
+  nhandles = 1;
+  for (i = 0; i < nfd; i++)
+    {
+      int happened;
+
+      if (pfd[i].fd < 0)
+        continue;
+      if (!(pfd[i].events & (POLLIN | POLLRDNORM |
+                             POLLOUT | POLLWRNORM | POLLWRBAND)))
+        continue;
+
+      h = (HANDLE) HandleFromFd (pfd[i].fd);
+      if (h != handle_array[nhandles])
+        {
+          /* It's a socket.  */
+          WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+          WSAEventSelect ((SOCKET) h, 0, 0);
+
+          /* If we're lucky, WSAEnumNetworkEvents already provided a way
+             to distinguish FD_READ and FD_ACCEPT; this saves a recv later.  */
+          if (FD_ISSET ((SOCKET) h, &rfds)
+              && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
+            ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
+          if (FD_ISSET ((SOCKET) h, &wfds))
+            ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
+          if (FD_ISSET ((SOCKET) h, &xfds))
+            ev.lNetworkEvents |= FD_OOB;
+
+          happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events,
+                                                     ev.lNetworkEvents);
+        }
+      else
+        {
+          /* Not a socket.  */
+          int sought = pfd[i].events;
+          happened = windows_compute_revents (h, &sought);
+          nhandles++;
+        }
+
+       if ((pfd[i].revents |= happened) != 0)
+        rc++;
+    }
+
+  if (!rc && timeout == INFTIM)
+    {
+      SleepEx (1, TRUE);
+      goto restart;
+    }
+
+  return rc;
+#endif
+}
diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c
deleted file mode 100644
index cd888b5..0000000
--- a/src/pulsecore/poll.c
+++ /dev/null
@@ -1,237 +0,0 @@
-
-/***
-  This file is part of PulseAudio.
-
-  Copyright 2006 Pierre Ossman <ossman at 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, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-  USA.
-***/
-
-/***
-   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 */



More information about the pulseaudio-commits mailing list