| #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(); |
| } |
| }; |
|
|
| } |
| } |
|
|