diff --git a/libs/pbd/pbd/semutils.h b/libs/pbd/pbd/semutils.h index 7c91db3cad..fdf3cd7d4c 100644 --- a/libs/pbd/pbd/semutils.h +++ b/libs/pbd/pbd/semutils.h @@ -21,15 +21,19 @@ #ifndef __pbd_semutils_h__ #define __pbd_semutils_h__ +#define USE_FUTEX_SEMAPHORE + #if (defined PLATFORM_WINDOWS && !defined USE_PTW32_SEMAPHORE) #define WINDOWS_SEMAPHORE 1 #endif #ifdef WINDOWS_SEMAPHORE -#include +# include +#elif defined USE_FUTEX_SEMAPHORE +# include #else -#include -#include +# include +# include #endif #include "pbd/libpbd_visibility.h" @@ -44,6 +48,8 @@ class LIBPBD_API Semaphore { #elif __APPLE__ sem_t* _sem; sem_t* ptr_to_sem() const { return _sem; } +#elif defined USE_FUTEX_SEMAPHORE + std::atomic _value; #else mutable sem_t _sem; sem_t* ptr_to_sem() const { return &_sem; } @@ -53,7 +59,7 @@ class LIBPBD_API Semaphore { Semaphore (const char* name, int val); ~Semaphore (); -#ifdef WINDOWS_SEMAPHORE +#if defined WINDOWS_SEMAPHORE || defined USE_FUTEX_SEMAPHORE int signal (); int wait (); diff --git a/libs/pbd/semutils.cc b/libs/pbd/semutils.cc index ab2928ee79..ba7b4e2bcb 100644 --- a/libs/pbd/semutils.cc +++ b/libs/pbd/semutils.cc @@ -20,6 +20,13 @@ #include "pbd/semutils.h" #include "pbd/failed_constructor.h" +#ifdef USE_FUTEX_SEMAPHORE +#include +#include +#include +#include +#endif + using namespace PBD; Semaphore::Semaphore (const char* name, int val) @@ -41,6 +48,9 @@ Semaphore::Semaphore (const char* name, int val) throw failed_constructor (); } +#elif defined USE_FUTEX_SEMAPHORE + (void)name; /* stop warning */ + _value = val; #else (void) name; /* stop gcc warning on !Apple systems */ @@ -88,4 +98,45 @@ Semaphore::reset () return rv; } +#elif defined USE_FUTEX_SEMAPHORE + +int +Semaphore::signal () +{ + std::atomic_fetch_add_explicit (&_value, 1, std::memory_order_release); + return syscall (__NR_futex, &_value, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0); +} + +int +Semaphore::wait () +{ + unsigned int value = 1; + while (!std::atomic_compare_exchange_weak_explicit (&_value, &value, value - 1, std::memory_order_acquire, std::memory_order_relaxed)) { + if (value == 0) { + if (syscall (__NR_futex, &_value, FUTEX_WAIT_PRIVATE, 0, NULL, NULL, 0)) { + if (errno != EAGAIN && errno != EINTR) { + return 1; + } + } + value = 1; + } + } + return 0; +} + +int +Semaphore::reset () +{ + int rv = 0; + unsigned int value = 1; + + while (!std::atomic_compare_exchange_weak_explicit (&_value, &value, value - 1, std::memory_order_acquire, std::memory_order_relaxed)) { + if (value == 0) { + break; + } + ++rv; + } + return rv; +} + #endif