|
1 | 1 | #pragma once
|
2 | 2 |
|
3 | 3 | #include <cstdint>
|
| 4 | +#include <string> |
| 5 | +#include <mutex> |
4 | 6 |
|
5 | 7 | #include <Windows.h>
|
6 | 8 |
|
7 | 9 | #include "libipc/utility/log.h"
|
| 10 | +#include "libipc/utility/scope_guard.h" |
| 11 | +#include "libipc/platform/detail.h" |
8 | 12 | #include "libipc/mutex.h"
|
| 13 | +#include "libipc/semaphore.h" |
| 14 | +#include "libipc/shm.h" |
9 | 15 |
|
10 | 16 | namespace ipc {
|
11 | 17 | namespace detail {
|
12 | 18 | namespace sync {
|
13 | 19 |
|
14 | 20 | class condition {
|
15 |
| - HANDLE h_ = NULL; |
| 21 | + ipc::sync::semaphore sem_; |
| 22 | + ipc::sync::mutex lock_; |
| 23 | + ipc::shm::handle shm_; |
| 24 | + |
| 25 | + std::int32_t &counter() { |
| 26 | + return *static_cast<std::int32_t *>(shm_.get()); |
| 27 | + } |
16 | 28 |
|
17 | 29 | public:
|
18 |
| - condition() noexcept = default; |
| 30 | + condition() = default; |
19 | 31 | ~condition() noexcept = default;
|
20 | 32 |
|
21 |
| - HANDLE native() const noexcept { |
22 |
| - return h_; |
| 33 | + auto native() noexcept { |
| 34 | + return sem_.native(); |
| 35 | + } |
| 36 | + |
| 37 | + auto native() const noexcept { |
| 38 | + return sem_.native(); |
23 | 39 | }
|
24 | 40 |
|
25 | 41 | bool valid() const noexcept {
|
26 |
| - return h_ != NULL; |
| 42 | + return sem_.valid() && lock_.valid() && shm_.valid(); |
27 | 43 | }
|
28 | 44 |
|
29 | 45 | bool open(char const *name) noexcept {
|
30 | 46 | close();
|
| 47 | + if (!sem_.open((std::string{"_cond_sem_"} + name).c_str())) { |
| 48 | + return false; |
| 49 | + } |
| 50 | + auto finally_sem = ipc::guard([this] { sem_.close(); }); // close when failed |
| 51 | + if (!lock_.open((std::string{"_cond_lock_"} + name).c_str())) { |
| 52 | + return false; |
| 53 | + } |
| 54 | + auto finally_lock = ipc::guard([this] { lock_.close(); }); // close when failed |
| 55 | + if (!shm_.acquire((std::string{"_cond_shm_"} + name).c_str(), sizeof(std::int32_t))) { |
| 56 | + return false; |
| 57 | + } |
| 58 | + finally_lock.dismiss(); |
| 59 | + finally_sem.dismiss(); |
31 | 60 | return valid();
|
32 | 61 | }
|
33 | 62 |
|
34 | 63 | void close() noexcept {
|
35 | 64 | if (!valid()) return;
|
36 |
| - ::CloseHandle(h_); |
37 |
| - h_ = NULL; |
| 65 | + sem_.close(); |
| 66 | + lock_.close(); |
| 67 | + shm_.release(); |
38 | 68 | }
|
39 | 69 |
|
40 | 70 | bool wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept {
|
41 |
| - return true; |
| 71 | + if (!valid()) return false; |
| 72 | + auto &cnt = counter(); |
| 73 | + { |
| 74 | + IPC_UNUSED_ std::lock_guard<ipc::sync::mutex> guard {lock_}; |
| 75 | + cnt = (cnt < 0) ? 1 : cnt + 1; |
| 76 | + } |
| 77 | + DWORD ms = (tm == invalid_value) ? INFINITE : static_cast<DWORD>(tm); |
| 78 | + /** |
| 79 | + * @see |
| 80 | + * - https://www.microsoft.com/en-us/research/wp-content/uploads/2004/12/ImplementingCVs.pdf |
| 81 | + * - https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-signalobjectandwait |
| 82 | + */ |
| 83 | + bool rs = ::SignalObjectAndWait(mtx.native(), sem_.native(), ms, FALSE) == WAIT_OBJECT_0; |
| 84 | + bool rl = mtx.lock(); // INFINITE |
| 85 | + if (!rs) { |
| 86 | + IPC_UNUSED_ std::lock_guard<ipc::sync::mutex> guard {lock_}; |
| 87 | + cnt -= 1; |
| 88 | + } |
| 89 | + return rs && rl; |
42 | 90 | }
|
43 | 91 |
|
44 | 92 | bool notify() noexcept {
|
45 |
| - return true; |
| 93 | + if (!valid()) return false; |
| 94 | + auto &cnt = counter(); |
| 95 | + if (!lock_.lock()) return false; |
| 96 | + bool ret = false; |
| 97 | + if (cnt > 0) { |
| 98 | + ret = sem_.post(1); |
| 99 | + cnt -= 1; |
| 100 | + } |
| 101 | + return lock_.unlock() && ret; |
46 | 102 | }
|
47 | 103 |
|
48 | 104 | bool broadcast() noexcept {
|
49 |
| - return true; |
| 105 | + if (!valid()) return false; |
| 106 | + auto &cnt = counter(); |
| 107 | + if (!lock_.lock()) return false; |
| 108 | + bool ret = false; |
| 109 | + if (cnt > 0) { |
| 110 | + ret = sem_.post(cnt); |
| 111 | + cnt = 0; |
| 112 | + } |
| 113 | + return lock_.unlock() && ret; |
50 | 114 | }
|
51 | 115 | };
|
52 | 116 |
|
|
0 commit comments