Implement Futex semaphore

This commit is contained in:
Robin Gareus
2022-05-11 23:42:33 +02:00
parent 83d0892777
commit 34678c094a
2 changed files with 61 additions and 4 deletions

View File

@@ -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 <windows.h>
# include <windows.h>
#elif defined USE_FUTEX_SEMAPHORE
# include <atomic>
#else
#include <pthread.h>
#include <semaphore.h>
# include <pthread.h>
# include <semaphore.h>
#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<unsigned int> _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 ();

View File

@@ -20,6 +20,13 @@
#include "pbd/semutils.h"
#include "pbd/failed_constructor.h"
#ifdef USE_FUTEX_SEMAPHORE
#include <errno.h>
#include <linux/futex.h>
#include <syscall.h>
#include <unistd.h>
#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