From e09ea90949d58b5d75724796068288732babf8f7 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Wed, 16 Jan 2019 17:03:34 +0800 Subject: [PATCH] implement waiter_linux.h --- src/platform/waiter_linux.h | 86 ++++++++++++++++++++++++++++++++++--- src/platform/waiter_win.h | 2 +- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/platform/waiter_linux.h b/src/platform/waiter_linux.h index fcc3565..2808ced 100644 --- a/src/platform/waiter_linux.h +++ b/src/platform/waiter_linux.h @@ -1,32 +1,106 @@ #pragma once +#include + +#include +#include +#include +#include + +namespace std { + +// deduction guides for std::unique_ptr +template +unique_ptr(T* p, D&& d) -> unique_ptr>; + +} // namespace std + namespace ipc { namespace detail { class waiter { + pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t cond_ = PTHREAD_COND_INITIALIZER; + std::atomic counter_ { 0 }; + public: using handle_t = void*; +private: + constexpr static waiter* waiter_cast(handle_t h) { + return static_cast(h); + } + +public: constexpr static handle_t invalid() { return nullptr; } handle_t open(char const * name) { if (name == nullptr || name[0] == '\0') return invalid(); - return invalid(); + if (counter_.fetch_add(1, std::memory_order_acq_rel) == 0) { + // init mutex + pthread_mutexattr_t mutex_attr; + if (::pthread_mutexattr_init(&mutex_attr) != 0) { + return invalid(); + } + [[maybe_unused]] auto guard_mutex_attr = std::unique_ptr { &mutex_attr, ::pthread_mutexattr_destroy }; + if (::pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED) != 0) { + return invalid(); + } + if (::pthread_mutex_init(&mutex_, &mutex_attr) != 0) { + return invalid(); + } + auto guard_mutex = std::unique_ptr { &mutex_, ::pthread_mutex_destroy }; + // init condition + pthread_condattr_t cond_attr; + if (::pthread_condattr_init(&cond_attr) != 0) { + return invalid(); + } + [[maybe_unused]] auto guard_cond_attr = std::unique_ptr { &cond_attr, ::pthread_condattr_destroy }; + if (::pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED) != 0) { + return invalid(); + } + if (::pthread_cond_init(&cond_, &cond_attr) != 0) { + return invalid(); + } + // no need to guard condition + // release guards + guard_mutex.release(); + } + return this; } - static void close(handle_t /*h*/) { + void close(handle_t h) { + if (h == invalid()) return; + auto w = waiter_cast(h); + if (w->counter_.fetch_sub(1, std::memory_order_acq_rel) == 1) { + ::pthread_cond_destroy (&(w->cond_ )); + ::pthread_mutex_destroy(&(w->mutex_)); + } } - bool wait(handle_t /*h*/) { - return false; + bool wait(handle_t h) { + if (h == invalid()) return false; + auto w = waiter_cast(h); + if (::pthread_mutex_lock(&(w->mutex_)) != 0) { + return false; + } + [[maybe_unused]] auto guard = std::unique_ptr { &(w->mutex_), ::pthread_mutex_unlock }; + if (::pthread_cond_wait(&(w->cond_), &(w->mutex_)) != 0) { + return false; + } + return true; } - void notify(handle_t /*h*/) { + void notify(handle_t h) { + if (h == invalid()) return; + ::pthread_cond_signal(&(waiter_cast(h)->cond_)); } - void broadcast(handle_t /*h*/) { + void broadcast(handle_t h) { + if (h == invalid()) return; + ::pthread_cond_broadcast(&(waiter_cast(h)->cond_)); } }; diff --git a/src/platform/waiter_win.h b/src/platform/waiter_win.h index ab0b046..8807088 100644 --- a/src/platform/waiter_win.h +++ b/src/platform/waiter_win.h @@ -27,7 +27,7 @@ public: return ::CreateSemaphore(NULL, 0, LONG_MAX, ipc::detail::to_tchar(name).c_str()); } - static void close(handle_t h) { + void close(handle_t h) { ::CloseHandle(h); }