Improve PBD::Semaphore performance

Skip syscall if no threads are waiting and decouple atomic
value from futex address so that FUTEX_WAIT does not fail.
This commit is contained in:
Robin Gareus 2022-05-12 04:49:11 +02:00
parent f849f3ce2c
commit 40fa6e2023
No known key found for this signature in database
GPG key ID: A090BCE02CF57F04
2 changed files with 14 additions and 23 deletions

View file

@ -47,7 +47,8 @@ class LIBPBD_API Semaphore {
sem_t* _sem; sem_t* _sem;
sem_t* ptr_to_sem() const { return _sem; } sem_t* ptr_to_sem() const { return _sem; }
#elif defined USE_FUTEX_SEMAPHORE #elif defined USE_FUTEX_SEMAPHORE
std::atomic<unsigned int> _value; int _futex;
std::atomic<int> _value;
#else #else
mutable sem_t _sem; mutable sem_t _sem;
sem_t* ptr_to_sem() const { return &_sem; } sem_t* ptr_to_sem() const { return &_sem; }

View file

@ -23,6 +23,7 @@
#ifdef USE_FUTEX_SEMAPHORE #ifdef USE_FUTEX_SEMAPHORE
#include <errno.h> #include <errno.h>
#include <linux/futex.h> #include <linux/futex.h>
#include <sched.h>
#include <syscall.h> #include <syscall.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -103,23 +104,19 @@ Semaphore::reset ()
int int
Semaphore::signal () Semaphore::signal ()
{ {
std::atomic_fetch_add_explicit (&_value, 1, std::memory_order_release); if (std::atomic_fetch_add_explicit (&_value, 1, std::memory_order_relaxed) < 0) {
return syscall (__NR_futex, &_value, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0); while (syscall (__NR_futex, &_futex, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0) < 1) {
sched_yield();
}
}
return 0;
} }
int int
Semaphore::wait () Semaphore::wait ()
{ {
unsigned int value = 1; if (std::atomic_fetch_sub_explicit (&_value, 1, std::memory_order_relaxed) <= 0) {
while (!std::atomic_compare_exchange_weak_explicit (&_value, &value, value - 1, std::memory_order_acquire, std::memory_order_relaxed)) { syscall(__NR_futex, &_futex, FUTEX_WAIT_PRIVATE, _futex, NULL, 0, 0);
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; return 0;
} }
@ -127,16 +124,9 @@ Semaphore::wait ()
int int
Semaphore::reset () Semaphore::reset ()
{ {
int rv = 0; int value = _value;
unsigned int value = 1; _value = 0;
return value;
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 #endif