1 #pragma once
2
3 #include <sdbusplus/async/execution.hpp>
4 #include <sdbusplus/event.hpp>
5
6 #include <queue>
7 #include <string>
8
9 namespace sdbusplus::async
10 {
11
12 namespace mutex_ns
13 {
14 struct mutex_completion;
15 } // namespace mutex_ns
16
17 class lock_guard;
18
19 class mutex
20 {
21 public:
22 mutex() = delete;
23 mutex(const mutex&) = delete;
24 mutex& operator=(const mutex&) = delete;
25 mutex(mutex&&) = delete;
26 mutex& operator=(mutex&&) = delete;
27 ~mutex() = default;
28
29 mutex(const std::string& name = "sdbusplus::async::mutex");
30
31 friend mutex_ns::mutex_completion;
32 friend lock_guard;
33
34 private:
35 void unlock();
36
37 std::string name;
38 bool locked{false};
39 std::queue<mutex_ns::mutex_completion*> waitingTasks;
40 std::mutex lock{};
41 };
42
43 // RAII wrapper for mutex for the duration of a scoped block.
44 class lock_guard
45 {
46 public:
47 lock_guard() = delete;
48 lock_guard(const lock_guard&) = delete;
49 lock_guard& operator=(const lock_guard&) = delete;
50 lock_guard(lock_guard&&) = delete;
51 lock_guard& operator=(lock_guard&&) = delete;
52
lock_guard(mutex & mutexInstance)53 explicit lock_guard(mutex& mutexInstance) : mutexInstance(mutexInstance) {}
54
~lock_guard()55 ~lock_guard()
56 {
57 if (owned)
58 {
59 mutexInstance.unlock();
60 owned = false;
61 }
62 }
63
64 auto lock() noexcept;
65 auto unlock() noexcept;
66
67 private:
68 mutex& mutexInstance;
69 bool owned = false;
70 };
71
72 namespace mutex_ns
73 {
74
75 struct mutex_completion
76 {
77 mutex_completion() = delete;
78 mutex_completion(const mutex_completion&) = delete;
79 mutex_completion& operator=(const mutex_completion&) = delete;
80 mutex_completion(mutex_completion&&) = delete;
81 ~mutex_completion() = default;
82
mutex_completionsdbusplus::async::mutex_ns::mutex_completion83 explicit mutex_completion(mutex& mutexInstance) noexcept :
84 mutexInstance(mutexInstance) {};
85
86 friend mutex;
87
tag_invoke(execution::start_t,mutex_completion & self)88 friend void tag_invoke(execution::start_t, mutex_completion& self) noexcept
89 {
90 self.arm();
91 }
92
93 private:
94 virtual void complete() noexcept = 0;
95 virtual void stop() noexcept = 0;
96 void arm() noexcept;
97
98 mutex& mutexInstance;
99 };
100
101 // Implementation (templated based on Receiver) of mutex_completion.
102 template <execution::receiver Receiver>
103 struct mutex_operation : mutex_completion
104 {
mutex_operationsdbusplus::async::mutex_ns::mutex_operation105 mutex_operation(mutex& mutexInstance, Receiver r) :
106 mutex_completion(mutexInstance), receiver(std::move(r))
107 {}
108
109 private:
completesdbusplus::async::mutex_ns::mutex_operation110 void complete() noexcept override final
111 {
112 execution::set_value(std::move(receiver));
113 }
114
stopsdbusplus::async::mutex_ns::mutex_operation115 void stop() noexcept override final
116 {
117 execution::set_stopped(std::move(receiver));
118 }
119
120 Receiver receiver;
121 };
122
123 // mutex sender
124 struct mutex_sender
125 {
126 using is_sender = void;
127
128 mutex_sender() = delete;
mutex_sendersdbusplus::async::mutex_ns::mutex_sender129 explicit mutex_sender(mutex& mutexInstance) noexcept :
130 mutexInstance(mutexInstance) {};
131
132 friend auto tag_invoke(execution::get_completion_signatures_t,
133 const mutex_sender&, auto)
134 -> execution::completion_signatures<execution::set_value_t(),
135 execution::set_stopped_t()>;
136
137 template <execution::receiver R>
tag_invoke(execution::connect_t,mutex_sender && self,R r)138 friend auto tag_invoke(execution::connect_t, mutex_sender&& self, R r)
139 -> mutex_operation<R>
140 {
141 return {self.mutexInstance, std::move(r)};
142 }
143
144 private:
145 mutex& mutexInstance;
146 };
147
148 } // namespace mutex_ns
149
lock()150 inline auto lock_guard::lock() noexcept
151 {
152 owned = true;
153 return mutex_ns::mutex_sender{this->mutexInstance};
154 }
155
unlock()156 inline auto lock_guard::unlock() noexcept
157 {
158 if (owned)
159 {
160 mutexInstance.unlock();
161 owned = false;
162 }
163 }
164
165 } // namespace sdbusplus::async
166