Timed wait operation for semaphore

This commit is contained in:
Jean Pierre Cimalando 2021-03-18 02:11:32 +01:00
parent da8e88f9f3
commit 520ae553f0
2 changed files with 61 additions and 2 deletions

View file

@ -8,6 +8,7 @@
#include <limits.h>
#include <string>
#include <cerrno>
#include <ctime>
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

View file

@ -12,6 +12,7 @@
#else
#include <semaphore.h>
#endif
#include <cstdint>
#include <system_error>
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);