source: mainline/uspace/lib/cpp/include/__bits/thread/mutex.hpp@ b57ba05

Last change on this file since b57ba05 was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

  • Property mode set to 100644
File size: 12.7 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2018 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_THREAD_MUTEX
8#define LIBCPP_BITS_THREAD_MUTEX
9
10#include <__bits/thread/threading.hpp>
11#include <functional>
12#include <thread>
13
14namespace std
15{
16 /**
17 * 20.4.1.2.1, class mutex:
18 */
19
20 class mutex
21 {
22 public:
23 constexpr mutex() noexcept
24 : mtx_{}
25 {
26 aux::threading::mutex::init(mtx_);
27 }
28
29 ~mutex() = default;
30
31 mutex(const mutex&) = delete;
32 mutex& operator=(const mutex&) = delete;
33
34 void lock();
35 bool try_lock();
36 void unlock();
37
38 using native_handle_type = aux::mutex_t*;
39 native_handle_type native_handle();
40
41 private:
42 aux::mutex_t mtx_;
43 };
44
45 /**
46 * 30.4.1.2.2, class recursive_mutex:
47 */
48
49 class recursive_mutex
50 {
51 public:
52 constexpr recursive_mutex() noexcept
53 : mtx_{}, lock_level_{}, owner_{}
54 {
55 aux::threading::mutex::init(mtx_);
56 }
57
58 ~recursive_mutex();
59
60 recursive_mutex(const recursive_mutex&) = delete;
61 recursive_mutex& operator=(const recursive_mutex&) = delete;
62
63 void lock();
64 bool try_lock() noexcept;
65 void unlock();
66
67 using native_handle_type = aux::mutex_t*;
68 native_handle_type native_handle();
69
70 private:
71 aux::mutex_t mtx_;
72 size_t lock_level_;
73 thread::id owner_;
74 };
75
76 /**
77 * 30.4.1.3.1, class timed_mutex:
78 */
79
80 class timed_mutex
81 {
82 public:
83 timed_mutex() noexcept;
84 ~timed_mutex();
85
86 timed_mutex(const timed_mutex&) = delete;
87 timed_mutex& operator=(const timed_mutex&) = delete;
88
89 void lock();
90 bool try_lock();
91 void unlock();
92
93 template<class Rep, class Period>
94 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
95 {
96 auto time = aux::threading::time::convert(rel_time);
97
98 return aux::threading::mutex::try_lock_for(time);
99 }
100
101 template<class Clock, class Duration>
102 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
103 {
104 auto dur = (abs_time - Clock::now());
105 auto time = aux::threading::time::convert(dur);
106
107 return aux::threading::mutex::try_lock_for(time);
108 }
109
110 using native_handle_type = aux::mutex_t*;
111 native_handle_type native_handle();
112
113 private:
114 aux::mutex_t mtx_;
115 };
116
117 /**
118 * 30.4.1.3.2, class recursive_timed_mutex:
119 */
120
121 class recursive_timed_mutex
122 {
123 public:
124 recursive_timed_mutex() noexcept
125 : mtx_{}, lock_level_{}, owner_{}
126 {
127 aux::threading::mutex::init(mtx_);
128 }
129
130 ~recursive_timed_mutex();
131
132 recursive_timed_mutex(const recursive_timed_mutex&) = delete;
133 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
134
135 void lock();
136 bool try_lock() noexcept;
137 void unlock();
138
139 template<class Rep, class Period>
140 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
141 {
142 if (owner_ == this_thread::get_id())
143 return true;
144
145 auto time = aux::threading::time::convert(rel_time);
146 auto ret = aux::threading::mutex::try_lock_for(time);
147
148 if (ret)
149 ++lock_level_;
150 return ret;
151 }
152
153 template<class Clock, class Duration>
154 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
155 {
156 if (owner_ == this_thread::get_id())
157 return true;
158
159 auto dur = (abs_time - Clock::now());
160 auto time = aux::threading::time::convert(dur);
161 auto ret = aux::threading::mutex::try_lock_for(time);
162
163 if (ret)
164 ++lock_level_;
165 return ret;
166 }
167
168 using native_handle_type = aux::mutex_t*;
169 native_handle_type native_handle();
170
171 private:
172 aux::mutex_t mtx_;
173 size_t lock_level_;
174 thread::id owner_;
175 };
176
177 struct defer_lock_t
178 { /* DUMMY BODY */ };
179
180 struct try_to_lock_t
181 { /* DUMMY BODY */ };
182
183 struct adopt_lock_t
184 { /* DUMMY BODY */ };
185
186 constexpr defer_lock_t defer_lock
187 { /* DUMMY BODY */ };
188
189 constexpr try_to_lock_t try_to_lock
190 { /* DUMMY BODY */ };
191
192 constexpr adopt_lock_t adopt_lock
193 { /* DUMMY BODY */ };
194
195 /**
196 * 30.4.2.1, class template lock_guard:
197 */
198
199 template<class Mutex>
200 class lock_guard
201 {
202 public:
203 using mutex_type = Mutex;
204
205 explicit lock_guard(mutex_type& mtx)
206 : mtx_{mtx}
207 {
208 mtx.lock();
209 }
210
211 lock_guard(mutex_type& mtx, adopt_lock_t)
212 : mtx_{mtx}
213 { /* DUMMY BODY */ }
214
215 ~lock_guard()
216 {
217 mtx_.unlock();
218 }
219
220 lock_guard(const lock_guard&) = delete;
221 lock_guard& operator=(const lock_guard&) = delete;
222
223 private:
224 mutex_type& mtx_;
225 };
226
227 template<class Mutex>
228 class unique_lock
229 {
230 public:
231 using mutex_type = Mutex;
232
233 /**
234 * 30.4.2.2.1, construction/copy/destroy:
235 */
236
237 unique_lock() noexcept
238 : mtx_{nullptr}, owns_{false}
239 { /* DUMMY BODY */ }
240
241 explicit unique_lock(mutex_type& mtx)
242 : mtx_{&mtx}, owns_{true}
243 {
244 mtx_->lock();
245 }
246
247 unique_lock(mutex_type& mtx, defer_lock_t) noexcept
248 : mtx_{&mtx}, owns_{false}
249 { /* DUMMY BODY */ }
250
251 unique_lock(mutex_type& mtx, try_to_lock_t)
252 : mtx_{&mtx}, owns_{}
253 {
254 owns_ = mtx_->try_lock();
255 }
256
257 unique_lock(mutex_type& mtx, adopt_lock_t)
258 : mtx_{&mtx}, owns_{true}
259 { /* DUMMY BODY */ }
260
261 template<class Clock, class Duration>
262 unique_lock(mutex_type& mtx, const chrono::time_point<Clock, Duration>& abs_time)
263 : mtx_{&mtx}, owns_{}
264 {
265 owns_ = mtx_->try_lock_until(abs_time);
266 }
267
268 template<class Rep, class Period>
269 unique_lock(mutex_type& mtx, const chrono::duration<Rep, Period>& rel_time)
270 : mtx_{&mtx}, owns_{}
271 {
272 owns_ = mtx_->try_lock_for(rel_time);
273 }
274
275 ~unique_lock()
276 {
277 if (owns_)
278 mtx_->unlock();
279 }
280
281 unique_lock(const unique_lock&) = delete;
282 unique_lock& operator=(const unique_lock&) = delete;
283
284 unique_lock(unique_lock&& other) noexcept
285 : mtx_{move(other.mtx_)}, owns_{move(other.owns_)}
286 {
287 other.mtx_ = nullptr;
288 other.owns_ = false;
289 }
290
291 unique_lock& operator=(unique_lock&& other)
292 {
293 if (owns_)
294 mtx_->unlock();
295
296 mtx_ = move(other.mtx_);
297 owns_ = move(other.owns_);
298
299 other.mtx_ = nullptr;
300 other.owns_ = false;
301 }
302
303 /**
304 * 30.4.2.2.2, locking:
305 */
306
307 void lock()
308 {
309 /**
310 * TODO:
311 * throw system_error operation_not_permitted if mtx_ == nullptr
312 * throw system_error resource_deadlock_would_occur if owns_ == true
313 */
314
315 mtx_->lock();
316 owns_ = true;
317 }
318
319 bool try_lock()
320 {
321 /**
322 * TODO:
323 * throw system_error operation_not_permitted if mtx_ == nullptr
324 * throw system_error resource_deadlock_would_occur if owns_ == true
325 */
326
327 owns_ = mtx_->try_lock();
328
329 return owns_;
330 }
331
332 template<class Rep, class Period>
333 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
334 {
335 /**
336 * TODO:
337 * throw system_error operation_not_permitted if mtx_ == nullptr
338 * throw system_error resource_deadlock_would_occur if owns_ == true
339 */
340
341 owns_ = mtx_->try_lock_for(rel_time);
342
343 return owns_;
344 }
345
346 template<class Clock, class Duration>
347 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
348 {
349 /**
350 * TODO:
351 * throw system_error operation_not_permitted if mtx_ == nullptr
352 * throw system_error resource_deadlock_would_occur if owns_ == true
353 */
354
355 owns_ = mtx_->try_lock_until(abs_time);
356
357 return owns_;
358 }
359
360 void unlock()
361 {
362 /**
363 * TODO:
364 * throw system_error operation_not_permitted if owns_ == false
365 */
366
367 mtx_->unlock();
368 }
369
370 /**
371 * 30.4.2.2.3, modifiers:
372 */
373
374 void swap(unique_lock& other) noexcept
375 {
376 std::swap(mtx_, other.mtx_);
377 std::swap(owns_, other.owns_);
378 }
379
380 mutex_type* release() noexcept
381 {
382 auto ret = mtx_;
383 mtx_ = nullptr;
384 owns_ = false;
385
386 return ret;
387 }
388
389 /**
390 * 30.4.2.2.4, observers:
391 */
392
393 bool owns_lock() const noexcept
394 {
395 return owns_;
396 }
397
398 explicit operator bool() const noexcept
399 {
400 return owns_;
401 }
402
403 mutex_type* mutex() const noexcept
404 {
405 return mtx_;
406 }
407
408 private:
409 mutex_type* mtx_;
410 bool owns_;
411 };
412
413 template<class Mutex>
414 void swap(unique_lock<Mutex>& lhs, unique_lock<Mutex>& rhs) noexcept
415 {
416 lhs.swap(rhs);
417 }
418
419 namespace aux
420 {
421 template<class L>
422 int try_lock_tail(int idx, L& l)
423 {
424 if (!l.try_lock())
425 return idx;
426 else
427 return -1;
428 }
429
430 template<class L1, class... L2>
431 int try_lock_tail(int idx, L1& l1, L2&... ls)
432 {
433 if (!l1.try_lock())
434 return idx;
435
436 auto ret = try_lock_tail(idx + 1, ls...);
437 if (ret != -1)
438 l1.unlock();
439
440 return ret;
441 }
442 }
443
444 template<class L1, class L2, class... L3>
445 int try_lock(L1& l1, L2& l2, L3&... ls)
446 {
447 return aux::try_lock_tail(0, l1, l2, ls...);
448 }
449
450 namespace aux
451 {
452 template<class L>
453 bool lock_tail(L& l)
454 {
455 return l.try_lock();
456 }
457
458 template<class L1, class... L2>
459 bool lock_tail(L1& l1, L2&... ls)
460 {
461 if (l1.try_lock())
462 {
463 auto ret = lock_tail(ls...);
464 if (ret)
465 return true;
466
467 l1.unlock();
468 }
469
470 return false;
471 }
472 }
473
474 template<class L1, class L2, class... L3>
475 void lock(L1& l1, L2& l2, L3&... ls)
476 {
477 do
478 {
479 l1.lock();
480
481 if (aux::lock_tail(l2, ls...))
482 return;
483 l1.unlock();
484 } while (true);
485 }
486
487 struct once_flag
488 {
489 constexpr once_flag() noexcept
490 : called_{false}, mtx_{}
491 { /* DUMMY BODY */ }
492
493 once_flag(const once_flag&) = delete;
494 once_flag& operator=(const once_flag&) = delete;
495
496 private:
497 bool called_;
498 mutex mtx_;
499
500 template<class Callable, class... Args>
501 friend void call_once(once_flag&, Callable&&, Args&&...);
502 };
503
504 template<class Callable, class... Args>
505 void call_once(once_flag& flag, Callable&& func, Args&&... args)
506 {
507 flag.mtx_.lock();
508 if (!flag.called_)
509 {
510 // TODO: exception handling
511
512 aux::INVOKE(forward<Callable>(func), forward<Args>(args)...);
513 flag.called_ = true;
514 }
515 flag.mtx_.unlock();
516 }
517}
518
519#endif
Note: See TracBrowser for help on using the repository browser.