| | #pragma once |
| |
|
| | #include <utility> |
| | #include <string> |
| | #include <mutex> |
| | #include <atomic> |
| |
|
| | #include "libipc/def.h" |
| | #include "libipc/mutex.h" |
| | #include "libipc/condition.h" |
| | #include "libipc/platform/detail.h" |
| |
|
| | namespace ipc { |
| | namespace detail { |
| |
|
| | class waiter { |
| | ipc::sync::condition cond_; |
| | ipc::sync::mutex lock_; |
| | std::atomic<bool> quit_ {false}; |
| |
|
| | public: |
| | static void init(); |
| |
|
| | waiter() = default; |
| | waiter(char const *name) { |
| | open(name); |
| | } |
| |
|
| | ~waiter() { |
| | close(); |
| | } |
| |
|
| | bool valid() const noexcept { |
| | return cond_.valid() && lock_.valid(); |
| | } |
| |
|
| | bool open(char const *name) noexcept { |
| | quit_.store(false, std::memory_order_relaxed); |
| | if (!cond_.open((std::string{"_waiter_cond_"} + name).c_str())) { |
| | return false; |
| | } |
| | if (!lock_.open((std::string{"_waiter_lock_"} + name).c_str())) { |
| | cond_.close(); |
| | return false; |
| | } |
| | return valid(); |
| | } |
| |
|
| | void close() noexcept { |
| | cond_.close(); |
| | lock_.close(); |
| | } |
| |
|
| | template <typename F> |
| | bool wait_if(F &&pred, std::uint64_t tm = ipc::invalid_value) noexcept { |
| | IPC_UNUSED_ std::lock_guard<ipc::sync::mutex> guard {lock_}; |
| | while ([this, &pred] { |
| | return !quit_.load(std::memory_order_relaxed) |
| | && std::forward<F>(pred)(); |
| | }()) { |
| | if (!cond_.wait(lock_, tm)) return false; |
| | } |
| | return true; |
| | } |
| |
|
| | bool notify() noexcept { |
| | std::lock_guard<ipc::sync::mutex>{lock_}; |
| | return cond_.notify(lock_); |
| | } |
| |
|
| | bool broadcast() noexcept { |
| | std::lock_guard<ipc::sync::mutex>{lock_}; |
| | return cond_.broadcast(lock_); |
| | } |
| |
|
| | bool quit_waiting() { |
| | quit_.store(true, std::memory_order_release); |
| | return broadcast(); |
| | } |
| | }; |
| |
|
| | } |
| | } |
| |
|