roo_threads
API Documentation for roo_threads
Loading...
Searching...
No Matches
mutex.h
Go to the documentation of this file.
1#pragma once
2
4
5#ifdef ROO_THREADS_USE_FREERTOS
6
7#include <cstdint>
8#include <utility>
9
10#include "freertos/FreeRTOS.h"
11#include "freertos/task.h"
13#include "roo_time.h"
14
15namespace roo_threads {
16/// @brief Backend namespace using FreeRTOS synchronization primitives.
17namespace freertos {
18
19/// @ingroup roo_threads_api_mutex
20/// @brief FreeRTOS backend implementation of `roo::mutex`.
21/// @copydoc roo_threads::doc::mutex
22class mutex {
23 public:
24 /// @copydoc roo_threads::doc::mutex::mutex
25 mutex() noexcept;
26 ~mutex() = default;
27
28 mutex(const mutex&) = delete;
29 mutex& operator=(const mutex&) = delete;
30
31 /// @copydoc roo_threads::doc::mutex::lock
32 void lock();
33 /// @copydoc roo_threads::doc::mutex::try_lock
34 bool try_lock();
35
36 /// @copydoc roo_threads::doc::mutex::unlock
37 void unlock();
38
39 private:
40 void ensureInitialized() noexcept;
41
42 StaticSemaphore_t mutex_;
43
44#if ROO_THREADS_FREERTOS_LAZY_INITIALIZE
45 bool initialized_ = false;
46#endif
47};
48
49template <typename Mutex>
50/// @ingroup roo_threads_api_mutex
51class lock_guard {
52 public:
53 typedef Mutex mutex_type;
54
55 /// @copydoc roo_threads::doc::lock_guard::lock_guard
56 explicit lock_guard(mutex_type& mutex) : mutex_(mutex) { mutex_.lock(); }
57
58 /// @copydoc roo_threads::doc::lock_guard::~lock_guard
59 ~lock_guard() { mutex_.unlock(); }
60
61 lock_guard(const lock_guard&) = delete;
62 lock_guard& operator=(const lock_guard&) = delete;
63
64 private:
65 mutex_type& mutex_;
66};
67
68// Do not lock the associated mutex.
69/// @ingroup roo_threads_api_mutex
70/// @copydoc roo_threads::doc::defer_lock_t
71struct defer_lock_t {
72 explicit defer_lock_t() = default;
73};
74
75// Try to lock the associated mutex without blocking.
76/// @ingroup roo_threads_api_mutex
77/// @copydoc roo_threads::doc::try_to_lock_t
78struct try_to_lock_t {
79 explicit try_to_lock_t() = default;
80};
81
82// Assume the calling thread already holds a non-shared lock (i.e., a lock
83// acquired by lock, try_lock, try_lock_for, or try_lock_until) on the mutex.
84/// @ingroup roo_threads_api_mutex
85/// @copydoc roo_threads::doc::adopt_lock_t
86struct adopt_lock_t {
87 explicit adopt_lock_t() = default;
88};
89
90// Tags for the unique_lock constructor.
91
92inline constexpr defer_lock_t defer_lock{};
93inline constexpr try_to_lock_t try_to_lock{};
94inline constexpr adopt_lock_t adopt_lock{};
95
96namespace internal {
97void checkLockOwned(bool owns);
98void checkLockUnowned(const void* lock, bool owns);
99} // namespace internal
100
101template <typename Mutex>
102/// @ingroup roo_threads_api_mutex
103class unique_lock {
104 public:
105 typedef Mutex mutex_type;
106
107 /// @copydoc roo_threads::doc::unique_lock::unique_lock() noexcept
108 unique_lock() noexcept : lock_(nullptr), owns_(false) {}
109
110 /// @copydoc roo_threads::doc::unique_lock::unique_lock(mutex_type&)
111 explicit unique_lock(mutex_type& mutex) : lock_(&mutex), owns_(false) {
112 lock();
113 }
114
115 /// @copydoc
116 /// roo_threads::doc::unique_lock::unique_lock(mutex_type&,defer_lock_t)
117 unique_lock(mutex_type& mutex, defer_lock_t) noexcept
118 : lock_(&mutex), owns_(false) {}
119
120 /// @copydoc
121 /// roo_threads::doc::unique_lock::unique_lock(mutex_type&,try_to_lock_t)
122 unique_lock(mutex_type& mutex, try_to_lock_t)
123 : lock_(&mutex), owns_(lock_->try_lock()) {}
124
125 /// @copydoc
126 /// roo_threads::doc::unique_lock::unique_lock(mutex_type&,adopt_lock_t)
127 unique_lock(mutex_type& mutex, adopt_lock_t) noexcept
128 : lock_(&mutex), owns_(true) {}
129
130 /// @copydoc
131 /// roo_threads::doc::unique_lock::unique_lock(mutex_type&,roo_time::Uptime)
132 unique_lock(mutex_type& mutex, roo_time::Uptime tp)
133 : lock_(&mutex), owns_(lock_->try_lock_until(tp)) {}
134
135 /// @copydoc
136 /// roo_threads::doc::unique_lock::unique_lock(mutex_type&,roo_time::Duration)
137 unique_lock(mutex_type& mutex, roo_time::Duration duration)
138 : lock_(&mutex), owns_(lock_->try_lock_for(duration)) {}
139
140 /// @copydoc roo_threads::doc::unique_lock::~unique_lock
141 ~unique_lock() {
142 if (owns_) unlock();
143 }
144
145 unique_lock(const unique_lock&) = delete;
146 unique_lock& operator=(const unique_lock&) = delete;
147
148 /// @copydoc roo_threads::doc::unique_lock::unique_lock(unique_lock&&)
149 unique_lock(unique_lock&& lock) noexcept
150 : lock_(lock.lock_), owns_(lock.owns_) {
151 lock.lock_ = 0;
152 lock.owns_ = false;
153 }
154
155 /// @copydoc roo_threads::doc::unique_lock::operator=(unique_lock&&)
156 unique_lock& operator=(unique_lock&& lock) noexcept {
157 if (owns_) unlock();
158
159 unique_lock(std::move(lock)).swap(*this);
160
161 lock.lock_ = 0;
162 lock.owns_ = false;
163
164 return *this;
165 }
166
167 /// @copydoc roo_threads::doc::unique_lock::lock
168 void lock() {
169 internal::checkLockUnowned(lock_, owns_);
170 lock_->lock();
171 owns_ = true;
172 }
173
174 /// @copydoc roo_threads::doc::unique_lock::try_lock
175 bool try_lock() {
176 internal::checkLockUnowned(lock_, owns_);
177 owns_ = lock_->try_lock();
178 return owns_;
179 }
180
181 /// @copydoc roo_threads::doc::unique_lock::try_lock_until
182 bool try_lock_until(roo_time::Uptime tp) {
183 internal::checkLockUnowned(lock_, owns_);
184 owns_ = lock_->try_lock_until(tp);
185 return owns_;
186 }
187
188 /// @copydoc roo_threads::doc::unique_lock::try_lock_for
189 bool try_lock_for(roo_time::Duration duration) {
190 internal::checkLockUnowned(lock_, owns_);
191 owns_ = lock_->try_lock_for(duration);
192 return owns_;
193 }
194
195 /// @copydoc roo_threads::doc::unique_lock::unlock
196 void unlock() {
197 internal::checkLockOwned(owns_);
198 if (lock_ != nullptr) {
199 lock_->unlock();
200 owns_ = false;
201 }
202 }
203
204 /// @copydoc roo_threads::doc::unique_lock::swap
205 void swap(unique_lock& other) noexcept {
206 std::swap(lock_, other.lock_);
207 std::swap(owns_, other.owns_);
208 }
209
210 /// @copydoc roo_threads::doc::unique_lock::release
211 mutex_type* release() noexcept {
212 mutex_type* ret = lock_;
213 lock_ = nullptr;
214 owns_ = false;
215 return ret;
216 }
217
218 /// @copydoc roo_threads::doc::unique_lock::owns_lock
219 bool owns_lock() const noexcept { return owns_; }
220
221 /// @copydoc roo_threads::doc::unique_lock::operator bool
222 explicit operator bool() const noexcept { return owns_lock(); }
223
224 /// @copydoc roo_threads::doc::unique_lock::mutex
225 mutex_type* mutex() const noexcept { return lock_; }
226
227 private:
228 mutex_type* lock_;
229 bool owns_;
230};
231
232} // namespace freertos
233} // namespace roo_threads
234
235#endif // ROO_THREADS_USE_FREERTOS