Created
April 12, 2020 18:54
-
-
Save jpcima/fab242de95e71d2f352372773f8a0c5e to your computer and use it in GitHub Desktop.
RTSemaphore v2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Jean Pierre Cimalando 2018-2020. | |
// Distributed under the Boost Software License, Version 1.0. | |
// (See accompanying file LICENSE or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
#include "RTSemaphore.h" | |
#include <limits.h> | |
#include <stdexcept> | |
#include <cerrno> | |
RTSemaphore::RTSemaphore(unsigned value) | |
{ | |
std::error_code ec; | |
init(ec, value); | |
if (ec) | |
throw std::system_error(ec); | |
good_ = true; | |
} | |
RTSemaphore::RTSemaphore(std::error_code &ec, unsigned value) noexcept | |
{ | |
init(ec, value); | |
good_ = ec ? false : true; | |
} | |
RTSemaphore::~RTSemaphore() noexcept | |
{ | |
if (good_) { | |
std::error_code ec; | |
destroy(ec); | |
} | |
} | |
void RTSemaphore::post() | |
{ | |
std::error_code ec; | |
post(ec); | |
if (ec) | |
throw std::system_error(ec); | |
} | |
void RTSemaphore::wait() | |
{ | |
std::error_code ec; | |
wait(ec); | |
if (ec) | |
throw std::system_error(ec); | |
} | |
bool RTSemaphore::try_wait() | |
{ | |
std::error_code ec; | |
bool b = try_wait(ec); | |
if (ec) | |
throw std::system_error(ec); | |
return b; | |
} | |
#if defined(__APPLE__) | |
void RTSemaphore::init(std::error_code &ec, unsigned value) | |
{ | |
ec.clear(); | |
kern_return_t ret = semaphore_create(mach_task_self(), &sem_, SYNC_POLICY_FIFO, value); | |
if (ret != KERN_SUCCESS) | |
ec = std::error_code(ret, mach_category()); | |
} | |
void RTSemaphore::destroy(std::error_code &ec) | |
{ | |
ec.clear(); | |
kern_return_t ret = semaphore_destroy(mach_task_self(), sem_); | |
if (ret != KERN_SUCCESS) | |
ec = std::error_code(ret, mach_category()); | |
} | |
void RTSemaphore::post(std::error_code &ec) noexcept | |
{ | |
ec.clear(); | |
kern_return_t ret = semaphore_signal(sem_); | |
if (ret != KERN_SUCCESS) | |
ec = std::error_code(ret, mach_category()); | |
} | |
void RTSemaphore::wait(std::error_code &ec) noexcept | |
{ | |
ec.clear(); | |
do { | |
kern_return_t ret = semaphore_wait(sem_); | |
switch (ret) { | |
case KERN_SUCCESS: | |
return; | |
case KERN_ABORTED: | |
break; | |
default: | |
ec = std::error_code(ret, mach_category()); | |
return; | |
} | |
} while (1); | |
} | |
bool RTSemaphore::try_wait(std::error_code &ec) noexcept | |
{ | |
ec.clear(); | |
do { | |
const mach_timespec_t timeout = {0, 0}; | |
kern_return_t ret = semaphore_timedwait(sem_, timeout); | |
switch (ret) { | |
case KERN_SUCCESS: | |
return true; | |
case KERN_OPERATION_TIMED_OUT: | |
return false; | |
case KERN_ABORTED: | |
break; | |
default: | |
ec = std::error_code(ret, mach_category()); | |
return; | |
} | |
} while (1); | |
} | |
const std::error_category &mach_category() | |
{ | |
class mach_category : public std::error_category { | |
public: | |
const char *name() const noexcept override | |
{ | |
return "kern_return_t"; | |
} | |
std::string message(int condition) const override | |
{ | |
const char *str = mach_error_string(condition); | |
return str ? str : ""; | |
} | |
}; | |
static const mach_category cat; | |
return cat; | |
} | |
#elif defined(_WIN32) | |
void RTSemaphore::init(std::error_code &ec, unsigned value) | |
{ | |
ec.clear(); | |
sem_ = CreateSemaphore(nullptr, value, LONG_MAX, nullptr); | |
if (!sem_) | |
ec = std::error_code(GetLastError(), std::system_category()); | |
} | |
void RTSemaphore::destroy(std::error_code &ec) | |
{ | |
ec.clear(); | |
if (CloseHandle(sem_) == 0) | |
ec = std::error_code(GetLastError(), std::system_category()); | |
} | |
void RTSemaphore::post(std::error_code &ec) noexcept | |
{ | |
ec.clear(); | |
if (ReleaseSemaphore(sem_, 1, nullptr) == 0) | |
ec = std::error_code(GetLastError(), std::system_category()); | |
} | |
void RTSemaphore::wait(std::error_code &ec) noexcept | |
{ | |
ec.clear(); | |
DWORD ret = WaitForSingleObject(sem_, INFINITE); | |
switch (ret) { | |
case WAIT_OBJECT_0: | |
return; | |
case WAIT_FAILED: | |
ec = std::error_code(GetLastError(), std::system_category()); | |
return; | |
default: | |
ec = std::error_code(ret, std::system_category()); | |
return; | |
} | |
} | |
bool RTSemaphore::try_wait(std::error_code &ec) noexcept | |
{ | |
ec.clear(); | |
DWORD ret = WaitForSingleObject(sem_, 0); | |
switch (ret) { | |
case WAIT_OBJECT_0: | |
return true; | |
case WAIT_TIMEOUT: | |
return false; | |
case WAIT_FAILED: | |
ec = std::error_code(GetLastError(), std::system_category()); | |
return false; | |
default: | |
ec = std::error_code(ret, std::system_category()); | |
return false; | |
} | |
} | |
#else | |
void RTSemaphore::init(std::error_code &ec, unsigned value) | |
{ | |
ec.clear(); | |
if (sem_init(&sem_, 0, value) != 0) | |
ec = std::error_code(errno, std::generic_category()); | |
} | |
void RTSemaphore::destroy(std::error_code &ec) | |
{ | |
ec.clear(); | |
if (sem_destroy(&sem_) != 0) | |
ec = std::error_code(errno, std::generic_category()); | |
} | |
void RTSemaphore::post(std::error_code &ec) noexcept | |
{ | |
ec.clear(); | |
while (sem_post(&sem_) != 0) { | |
int e = errno; | |
if (e != EINTR) { | |
ec = std::error_code(e, std::generic_category()); | |
return; | |
} | |
} | |
} | |
void RTSemaphore::wait(std::error_code &ec) noexcept | |
{ | |
ec.clear(); | |
while (sem_wait(&sem_) != 0) { | |
int e = errno; | |
if (e != EINTR) { | |
ec = std::error_code(e, std::generic_category()); | |
return; | |
} | |
} | |
} | |
bool RTSemaphore::try_wait(std::error_code &ec) noexcept | |
{ | |
ec.clear(); | |
do { | |
if (sem_trywait(&sem_) == 0) | |
return true; | |
int e = errno; | |
switch (e) { | |
case EINTR: | |
break; | |
case EAGAIN: | |
return false; | |
default: | |
ec = std::error_code(e, std::generic_category()); | |
return false; | |
} | |
} while (1); | |
} | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Jean Pierre Cimalando 2018-2020. | |
// Distributed under the Boost Software License, Version 1.0. | |
// (See accompanying file LICENSE or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
#pragma once | |
#if defined(__APPLE__) | |
#include <mach/mach.h> | |
#elif defined(_WIN32) | |
#include <windows.h> | |
#else | |
#include <semaphore.h> | |
#endif | |
#include <system_error> | |
class RTSemaphore { | |
public: | |
explicit RTSemaphore(unsigned value = 0); | |
explicit RTSemaphore(std::error_code &ec, unsigned value = 0) noexcept; | |
~RTSemaphore() noexcept; | |
RTSemaphore(const RTSemaphore &) = delete; | |
RTSemaphore &operator=(const RTSemaphore &) = delete; | |
explicit operator bool() const noexcept { return good_; } | |
void post(); | |
void wait(); | |
bool try_wait(); | |
void post(std::error_code &ec) noexcept; | |
void wait(std::error_code &ec) noexcept; | |
bool try_wait(std::error_code &ec) noexcept; | |
private: | |
void init(std::error_code &ec, unsigned value); | |
void destroy(std::error_code &ec); | |
private: | |
#if defined(__APPLE__) | |
semaphore_t sem_ {}; | |
static const std::error_category &mach_category(); | |
#elif defined(_WIN32) | |
HANDLE sem_ {}; | |
#else | |
sem_t sem_ {}; | |
#endif | |
bool good_ {}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment