From 520ae553f0a2614037d2430b7716154912d89174 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 18 Mar 2021 02:11:32 +0100 Subject: [PATCH] Timed wait operation for semaphore --- src/sfizz/RTSemaphore.cpp | 60 +++++++++++++++++++++++++++++++++++++-- src/sfizz/RTSemaphore.h | 3 ++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/sfizz/RTSemaphore.cpp b/src/sfizz/RTSemaphore.cpp index 685166e4..3397627c 100644 --- a/src/sfizz/RTSemaphore.cpp +++ b/src/sfizz/RTSemaphore.cpp @@ -8,6 +8,7 @@ #include #include #include +#include RTSemaphore::RTSemaphore(unsigned value) { @@ -57,6 +58,15 @@ bool RTSemaphore::try_wait() return b; } +bool RTSemaphore::timed_wait(uint32_t milliseconds) +{ + std::error_code ec; + bool b = timed_wait(milliseconds, ec); + if (ec) + throw std::system_error(ec); + return b; +} + #if defined(__APPLE__) void RTSemaphore::init(std::error_code& ec, unsigned value) { @@ -100,10 +110,17 @@ void RTSemaphore::wait(std::error_code& ec) noexcept } bool RTSemaphore::try_wait(std::error_code& ec) noexcept +{ + return timed_wait(0, ec); +} + +bool RTSemaphore::timed_wait(uint32_t milliseconds, std::error_code& ec) noexcept { ec.clear(); do { - const mach_timespec_t timeout = { 0, 0 }; + mach_timespec_t timeout; + timeout.tv_sec = milliseconds / 1000; + timeout.tv_nsec = (milliseconds % 1000) * (1000L * 1000L); kern_return_t ret = semaphore_timedwait(sem_, timeout); switch (ret) { case KERN_SUCCESS: @@ -178,9 +195,14 @@ void RTSemaphore::wait(std::error_code& ec) noexcept } bool RTSemaphore::try_wait(std::error_code& ec) noexcept +{ + return timed_wait(0, ec); +} + +bool RTSemaphore::timed_wait(uint32_t milliseconds, std::error_code& ec) noexcept { ec.clear(); - DWORD ret = WaitForSingleObject(sem_, 0); + DWORD ret = WaitForSingleObject(sem_, milliseconds); switch (ret) { case WAIT_OBJECT_0: return true; @@ -251,4 +273,38 @@ bool RTSemaphore::try_wait(std::error_code& ec) noexcept } } while (1); } + +static bool absolute_timeout(uint32_t milliseconds, timespec &abs, std::error_code& ec) +{ + timespec now; + if (clock_gettime(CLOCK_REALTIME, &now) != 0) { + ec = std::error_code(errno, std::generic_category()); + return false; + } + abs.tv_sec = now.tv_sec + milliseconds / 1000; + abs.tv_nsec = now.tv_nsec + (milliseconds % 1000) * (1000L * 1000L); + return true; +} + +bool RTSemaphore::timed_wait(uint32_t milliseconds, std::error_code& ec) noexcept +{ + ec.clear(); + timespec abs; + if (!absolute_timeout(milliseconds, abs, ec)) + return false; + do { + if (sem_timedwait(&sem_, &abs) == 0) + return true; + int e = errno; + switch (e) { + case EINTR: + break; + case ETIMEDOUT: + return false; + default: + ec = std::error_code(e, std::generic_category()); + return false; + } + } while (1); +} #endif diff --git a/src/sfizz/RTSemaphore.h b/src/sfizz/RTSemaphore.h index c17e5c2a..106a88ef 100644 --- a/src/sfizz/RTSemaphore.h +++ b/src/sfizz/RTSemaphore.h @@ -12,6 +12,7 @@ #else #include #endif +#include #include class RTSemaphore { @@ -28,10 +29,12 @@ public: void post(); void wait(); bool try_wait(); + bool timed_wait(uint32_t milliseconds); void post(std::error_code& ec) noexcept; void wait(std::error_code& ec) noexcept; bool try_wait(std::error_code& ec) noexcept; + bool timed_wait(uint32_t milliseconds, std::error_code& ec) noexcept; private: void init(std::error_code& ec, unsigned value);