diff options
-rw-r--r-- | src/pulsecore/fdsem.c | 119 |
1 files changed, 100 insertions, 19 deletions
diff --git a/src/pulsecore/fdsem.c b/src/pulsecore/fdsem.c index c81797e0..b919ba41 100644 --- a/src/pulsecore/fdsem.c +++ b/src/pulsecore/fdsem.c @@ -25,6 +25,7 @@ #include <config.h> #endif +#include <sys/syscall.h> #include <unistd.h> #include <errno.h> @@ -35,10 +36,37 @@ #include <pulsecore/core-util.h> #include <pulse/xmalloc.h> +#ifdef __linux__ + +#if !defined(__NR_eventfd) && defined(__i386__) +#define __NR_eventfd 323 +#endif + +#if !defined(__NR_eventfd) && defined(__x86_64__) +#define __NR_eventfd 284 +#endif + +#if !defined(SYS_eventfd) && defined(__NR_eventfd) +#define SYS_eventfd __NR_eventfd +#endif + +#ifdef SYS_eventfd +#define HAVE_EVENTFD + +static inline long eventfd(unsigned count) { + return syscall(SYS_eventfd, count); +} + +#endif +#endif + #include "fdsem.h" struct pa_fdsem { int fds[2]; +#ifdef HAVE_EVENTFD + int efd; +#endif pa_atomic_t waiting; pa_atomic_t signalled; pa_atomic_t in_pipe; @@ -48,25 +76,38 @@ pa_fdsem *pa_fdsem_new(void) { pa_fdsem *f; f = pa_xnew(pa_fdsem, 1); - - if (pipe(f->fds) < 0) { - pa_xfree(f); - return NULL; - } - pa_make_fd_cloexec(f->fds[0]); - pa_make_fd_cloexec(f->fds[1]); +#ifdef HAVE_EVENTFD + if ((f->efd = eventfd(0)) >= 0) { + pa_make_fd_cloexec(f->efd); + f->fds[0] = f->fds[1] = -1; + + } else +#endif + { + if (pipe(f->fds) < 0) { + pa_xfree(f); + return NULL; + } + + pa_make_fd_cloexec(f->fds[0]); + pa_make_fd_cloexec(f->fds[1]); + } pa_atomic_store(&f->waiting, 0); pa_atomic_store(&f->signalled, 0); pa_atomic_store(&f->in_pipe, 0); - + return f; } void pa_fdsem_free(pa_fdsem *f) { pa_assert(f); +#ifdef HAVE_EVENTFD + if (f->efd >= 0) + pa_close(f->efd); +#endif pa_close_pipe(f->fds); pa_xfree(f); @@ -81,12 +122,24 @@ static void flush(pa_fdsem *f) { do { char x[10]; - + +#ifdef HAVE_EVENTFD + if (f->efd >= 0) { + uint64_t u; + + if ((r = read(f->efd, &u, sizeof(u))) != sizeof(u)) { + pa_assert(r < 0 && errno == EINTR); + continue; + } + r = (ssize_t) u; + } else +#endif + if ((r = read(f->fds[0], &x, sizeof(x))) <= 0) { pa_assert(r < 0 && errno == EINTR); continue; } - + } while (pa_atomic_sub(&f->in_pipe, r) > r); } @@ -98,11 +151,22 @@ void pa_fdsem_post(pa_fdsem *f) { if (pa_atomic_load(&f->waiting)) { ssize_t r; char x = 'x'; - + pa_atomic_inc(&f->in_pipe); for (;;) { - + +#ifdef HAVE_EVENTFD + if (f->efd >= 0) { + uint64_t u = 1; + + if ((r = write(f->efd, &u, sizeof(u))) != sizeof(u)) { + pa_assert(r < 0 && errno == EINTR); + continue; + } + } else +#endif + if ((r = write(f->fds[1], &x, 1)) != 1) { pa_assert(r < 0 && errno == EINTR); continue; @@ -123,16 +187,29 @@ void pa_fdsem_wait(pa_fdsem *f) { return; pa_atomic_inc(&f->waiting); - + while (!pa_atomic_cmpxchg(&f->signalled, 1, 0)) { char x[10]; ssize_t r; - + +#ifdef HAVE_EVENTFD + if (f->efd >= 0) { + uint64_t u; + + if ((r = read(f->efd, &u, sizeof(u))) != sizeof(u)) { + pa_assert(r < 0 && errno == EINTR); + continue; + } + + r = (ssize_t) u; + } else +#endif + if ((r = read(f->fds[0], &x, sizeof(x))) <= 0) { pa_assert(r < 0 && errno == EINTR); continue; } - + pa_atomic_sub(&f->in_pipe, r); } @@ -143,17 +220,21 @@ int pa_fdsem_try(pa_fdsem *f) { pa_assert(f); flush(f); - + if (pa_atomic_cmpxchg(&f->signalled, 1, 0)) return 1; return 0; } - int pa_fdsem_get(pa_fdsem *f) { pa_assert(f); - + +#ifdef HAVE_EVENTFD + if (f->efd >= 0) + return f->efd; +#endif + return f->fds[0]; } @@ -170,7 +251,7 @@ int pa_fdsem_before_poll(pa_fdsem *f) { if (pa_atomic_cmpxchg(&f->signalled, 1, 0)) { pa_assert_se(pa_atomic_dec(&f->waiting) >= 1); return -1; - } + } return 0; } |