source: mainline/uspace/lib/cpp/include/impl/mutex.hpp@ b4b961b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b4b961b was b4b961b, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: added try_lock()

  • Property mode set to 100644
File size: 18.9 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_MUTEX
30#define LIBCPP_MUTEX
31
32#include <internal/common.hpp>
33#include <internal/thread.hpp>
34#include <thread>
35
36namespace std
37{
38 /**
39 * 20.4.1.2.1, class mutex:
40 */
41
42 class mutex
43 {
44 public:
45 constexpr mutex() noexcept
46 : mtx_{}
47 {
48 aux::threading::mutex::init(mtx_);
49 }
50
51 ~mutex();
52
53 mutex(const mutex&) = delete;
54 mutex& operator=(const mutex&) = delete;
55
56 void lock();
57 bool try_lock();
58 void unlock();
59
60 using native_handle_type = aux::mutex_t*;
61 native_handle_type native_handle();
62
63 private:
64 aux::mutex_t mtx_;
65 };
66
67 /**
68 * 30.4.1.2.2, class recursive_mutex:
69 */
70
71 class recursive_mutex
72 {
73 public:
74 constexpr recursive_mutex() noexcept
75 : mtx_{}, lock_level_{}, owner_{}
76 {
77 aux::threading::mutex::init(mtx_);
78 }
79
80 ~recursive_mutex();
81
82 recursive_mutex(const recursive_mutex&) = delete;
83 recursive_mutex& operator=(const recursive_mutex&) = delete;
84
85 void lock();
86 bool try_lock() noexcept;
87 void unlock();
88
89 using native_handle_type = aux::mutex_t*;
90 native_handle_type native_handle();
91
92 private:
93 aux::mutex_t mtx_;
94 size_t lock_level_;
95 thread::id owner_;
96 };
97
98 /**
99 * 30.4.1.3.1, class timed_mutex:
100 */
101
102 class timed_mutex
103 {
104 public:
105 timed_mutex() noexcept;
106 ~timed_mutex();
107
108 timed_mutex(const timed_mutex&) = delete;
109 timed_mutex& operator=(const timed_mutex&) = delete;
110
111 void lock();
112 bool try_lock();
113 void unlock();
114
115 template<class Rep, class Period>
116 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
117 {
118 auto time = aux::threading::time::convert(rel_time);
119
120 return aux::threading::mutex::try_lock_for(time);
121 }
122
123 template<class Clock, class Duration>
124 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
125 {
126 auto dur = (abs_time - Clock::now());
127 auto time = aux::threading::time::convert(dur);
128
129 return aux::threading::mutex::try_lock_for(time);
130 }
131
132 using native_handle_type = aux::mutex_t*;
133 native_handle_type native_handle();
134
135 private:
136 aux::mutex_t mtx_;
137 };
138
139 /**
140 * 30.4.1.3.2, class recursive_timed_mutex:
141 */
142
143 class recursive_timed_mutex
144 {
145 public:
146 recursive_timed_mutex() noexcept
147 : mtx_{}, lock_level_{}, owner_{}
148 {
149 aux::threading::mutex::init(mtx_);
150 }
151
152 ~recursive_timed_mutex();
153
154 recursive_timed_mutex(const recursive_timed_mutex&) = delete;
155 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
156
157 void lock();
158 bool try_lock() noexcept;
159 void unlock();
160
161 template<class Rep, class Period>
162 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
163 {
164 if (owner_ == this_thread::get_id())
165 return true;
166
167 auto time = aux::threading::time::convert(rel_time);
168 auto ret = aux::threading::mutex::try_lock_for(time);
169
170 if (ret)
171 ++lock_level_;
172 return ret;
173 }
174
175 template<class Clock, class Duration>
176 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
177 {
178 if (owner_ == this_thread::get_id())
179 return true;
180
181 auto dur = (abs_time - Clock::now());
182 auto time = aux::threading::time::convert(dur);
183 auto ret = aux::threading::mutex::try_lock_for(time);
184
185 if (ret)
186 ++lock_level_;
187 return ret;
188 }
189
190 using native_handle_type = aux::mutex_t*;
191 native_handle_type native_handle();
192
193 private:
194 aux::mutex_t mtx_;
195 size_t lock_level_;
196 thread::id owner_;
197 };
198
199 /**
200 * 30.4.1.4.1, class shared_timed_mutex:
201 */
202
203 // TODO: implement
204 class shared_timed_mutex;
205
206 struct defer_lock_t
207 { /* DUMMY BODY */ };
208
209 struct try_to_lock_t
210 { /* DUMMY BODY */ };
211
212 struct adopt_lock_t
213 { /* DUMMY BODY */ };
214
215 constexpr defer_lock_t defer_lock
216 { /* DUMMY BODY */ };
217
218 constexpr try_to_lock_t try_to_lock
219 { /* DUMMY BODY */ };
220
221 constexpr adopt_lock_t adopt_lock
222 { /* DUMMY BODY */ };
223
224 /**
225 * 30.4.2.1, class template lock_guard:
226 */
227
228 template<class Mutex>
229 class lock_guard
230 {
231 public:
232 using mutex_type = Mutex;
233
234 explicit lock_guard(mutex_type& mtx)
235 : mtx_{mtx}
236 {
237 mtx.lock();
238 }
239
240 lock_guard(mutex_type& mtx, adopt_lock_t)
241 : mtx_{mtx}
242 { /* DUMMY BODY */ }
243
244 ~lock_guard()
245 {
246 mtx_.unlock();
247 }
248
249 lock_guard(const lock_guard&) = delete;
250 lock_guard& operator=(const lock_guard&) = delete;
251
252 private:
253 mutex_type& mtx_;
254 };
255
256 template<class Mutex>
257 class unique_lock
258 {
259 public:
260 using mutex_type = Mutex;
261
262 /**
263 * 30.4.2.2.1, construction/copy/destroy:
264 */
265
266 unique_lock() noexcept
267 : mtx_{nullptr}, owns_{false}
268 { /* DUMMY BODY */ }
269
270 explicit unique_lock(mutex_type& mtx)
271 : mtx_{&mtx}, owns_{true}
272 {
273 mtx_->lock();
274 }
275
276 unique_lock(mutex_type& mtx, defer_lock_t) noexcept
277 : mtx_{&mtx}, owns_{false}
278 { /* DUMMY BODY */ }
279
280 unique_lock(mutex_type& mtx, try_to_lock_t)
281 : mtx_{&mtx}, owns_{}
282 {
283 owns_ = mtx_->try_lock();
284 }
285
286 unique_lock(mutex_type& mtx, adopt_lock_t)
287 : mtx_{&mtx}, owns_{true}
288 { /* DUMMY BODY */ }
289
290 template<class Clock, class Duration>
291 unique_lock(mutex_type& mtx, const chrono::time_point<Clock, Duration>& abs_time)
292 : mtx_{&mtx}, owns_{}
293 {
294 owns_ = mtx_->try_lock_until(abs_time);
295 }
296
297 template<class Rep, class Period>
298 unique_lock(mutex_type& mtx, const chrono::duration<Rep, Period>& rel_time)
299 : mtx_{&mtx}, owns_{}
300 {
301 owns_ = mtx_->try_lock_for(rel_time);
302 }
303
304 ~unique_lock()
305 {
306 if (owns_)
307 mtx_->unlock();
308 }
309
310 unique_lock(const unique_lock&) = delete;
311 unique_lock& operator=(const unique_lock&) = delete;
312
313 unique_lock(unique_lock&& other) noexcept
314 : mtx_{move(other.mtx_)}, owns_{move(other.owns_)}
315 {
316 other.mtx_ = nullptr;
317 other.owns_ = false;
318 }
319
320 unique_lock& operator=(unique_lock&& other)
321 {
322 if (owns_)
323 mtx_->unlock();
324
325 mtx_ = move(other.mtx_);
326 owns_ = move(other.owns_);
327
328 other.mtx_ = nullptr;
329 other.owns_ = false;
330 }
331
332 /**
333 * 30.4.2.2.2, locking:
334 */
335
336 void lock()
337 {
338 /**
339 * TODO:
340 * throw system_error operation_not_permitted if mtx_ == nullptr
341 * throw system_error resource_deadlock_would_occur if owns_ == true
342 */
343
344 mtx_->lock();
345 owns_ = true;
346 }
347
348 bool try_lock()
349 {
350 /**
351 * TODO:
352 * throw system_error operation_not_permitted if mtx_ == nullptr
353 * throw system_error resource_deadlock_would_occur if owns_ == true
354 */
355
356 owns_ = mtx_->try_lock();
357
358 return owns_;
359 }
360
361 template<class Rep, class Period>
362 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
363 {
364 /**
365 * TODO:
366 * throw system_error operation_not_permitted if mtx_ == nullptr
367 * throw system_error resource_deadlock_would_occur if owns_ == true
368 */
369
370 owns_ = mtx_->try_lock_for(rel_time);
371
372 return owns_;
373 }
374
375 template<class Clock, class Duration>
376 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
377 {
378 /**
379 * TODO:
380 * throw system_error operation_not_permitted if mtx_ == nullptr
381 * throw system_error resource_deadlock_would_occur if owns_ == true
382 */
383
384 owns_ = mtx_->try_lock_until(abs_time);
385
386 return owns_;
387 }
388
389 void unlock()
390 {
391 /**
392 * TODO:
393 * throw system_error operation_not_permitted if owns_ == false
394 */
395
396 mtx_->unlock();
397 }
398
399 /**
400 * 30.4.2.2.3, modifiers:
401 */
402
403 void swap(unique_lock& other) noexcept
404 {
405 std::swap(mtx_, other.mtx_);
406 std::swap(owns_, other.owns_);
407 }
408
409 mutex_type* release() noexcept
410 {
411 auto ret = mtx_;
412 mtx_ = nullptr;
413 owns_ = false;
414
415 return ret;
416 }
417
418 /**
419 * 30.4.2.2.4, observers:
420 */
421
422 bool owns_lock() const noexcept
423 {
424 return owns_;
425 }
426
427 explicit operator bool() const noexcept
428 {
429 return owns_;
430 }
431
432 mutex_type* mutex() const noexcept
433 {
434 return mtx_;
435 }
436
437 private:
438 mutex_type* mtx_;
439 bool owns_;
440 };
441
442 template<class Mutex>
443 void swap(unique_lock<Mutex>& lhs, unique_lock<Mutex>& rhs) noexcept
444 {
445 lhs.swap(rhs);
446 }
447
448 /**
449 * 30.4.2.3, class template shared_lock:
450 */
451
452 template<class Mutex>
453 class shared_lock
454 {
455 public:
456 using mutex_type = Mutex;
457
458 /**
459 * 30.4.2.2.1, construction/copy/destroy:
460 */
461
462 shared_lock() noexcept
463 : mtx_{nullptr}, owns_{false}
464 { /* DUMMY BODY */ }
465
466 explicit shared_lock(mutex_type& mtx)
467 : mtx_{&mtx}, owns_{true}
468 {
469 mtx_->lock_shared();
470 }
471
472 shared_lock(mutex_type& mtx, defer_lock_t) noexcept
473 : mtx_{&mtx}, owns_{false}
474 { /* DUMMY BODY */ }
475
476 shared_lock(mutex_type& mtx, try_to_lock_t)
477 : mtx_{&mtx}, owns_{}
478 {
479 owns_ = mtx_->try_lock_shared();
480 }
481
482 shared_lock(mutex_type& mtx, adopt_lock_t)
483 : mtx_{&mtx}, owns_{true}
484 { /* DUMMY BODY */ }
485
486 template<class Clock, class Duration>
487 shared_lock(mutex_type& mtx, const chrono::time_point<Clock, Duration>& abs_time)
488 : mtx_{&mtx}, owns_{}
489 {
490 owns_ = mtx_->try_lock_shared_until(abs_time);
491 }
492
493 template<class Rep, class Period>
494 shared_lock(mutex_type& mtx, const chrono::duration<Rep, Period>& rel_time)
495 : mtx_{&mtx}, owns_{}
496 {
497 owns_ = mtx_->try_lock_shared_for(rel_time);
498 }
499
500 ~shared_lock()
501 {
502 if (owns_)
503 mtx_->unlock_shared();
504 }
505
506 shared_lock(const shared_lock&) = delete;
507 shared_lock& operator=(const shared_lock&) = delete;
508
509 shared_lock(shared_lock&& other) noexcept
510 : mtx_{move(other.mtx_)}, owns_{move(other.owns_)}
511 {
512 other.mtx_ = nullptr;
513 other.owns_ = false;
514 }
515
516 shared_lock& operator=(shared_lock&& other)
517 {
518 if (owns_)
519 mtx_->unlock_shared();
520
521 mtx_ = move(other.mtx_);
522 owns_ = move(other.owns_);
523
524 other.mtx_ = nullptr;
525 other.owns_ = false;
526 }
527
528 /**
529 * 30.4.2.2.2, locking:
530 */
531
532 void lock()
533 {
534 /**
535 * TODO:
536 * throw system_error operation_not_permitted if mtx_ == nullptr
537 * throw system_error resource_deadlock_would_occur if owns_ == true
538 */
539
540 mtx_->lock_shared();
541 owns_ = true;
542 }
543
544 bool try_lock()
545 {
546 /**
547 * TODO:
548 * throw system_error operation_not_permitted if mtx_ == nullptr
549 * throw system_error resource_deadlock_would_occur if owns_ == true
550 */
551
552 owns_ = mtx_->try_lock_shared();
553
554 return owns_;
555 }
556
557 template<class Rep, class Period>
558 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
559 {
560 /**
561 * TODO:
562 * throw system_error operation_not_permitted if mtx_ == nullptr
563 * throw system_error resource_deadlock_would_occur if owns_ == true
564 */
565
566 owns_ = mtx_->try_lock_shared_for(rel_time);
567
568 return owns_;
569 }
570
571 template<class Clock, class Duration>
572 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
573 {
574 /**
575 * TODO:
576 * throw system_error operation_not_permitted if mtx_ == nullptr
577 * throw system_error resource_deadlock_would_occur if owns_ == true
578 */
579
580 owns_ = mtx_->try_lock_shared_until(abs_time);
581
582 return owns_;
583 }
584
585 void unlock()
586 {
587 /**
588 * TODO:
589 * throw system_error operation_not_permitted if owns_ == false
590 */
591
592 mtx_->unlock_shared();
593 }
594
595 /**
596 * 30.4.2.2.3, modifiers:
597 */
598
599 void swap(shared_lock& other) noexcept
600 {
601 std::swap(mtx_, other.mtx_);
602 std::swap(owns_, other.owns_);
603 }
604
605 mutex_type* release() noexcept
606 {
607 auto ret = mtx_;
608 mtx_ = nullptr;
609 owns_ = false;
610
611 return ret;
612 }
613
614 /**
615 * 30.4.2.2.4, observers:
616 */
617
618 bool owns_lock() const noexcept
619 {
620 return owns_;
621 }
622
623 explicit operator bool() const noexcept
624 {
625 return owns_;
626 }
627
628 mutex_type* mutex() const noexcept
629 {
630 return mtx_;
631 }
632
633 private:
634 mutex_type* mtx_;
635 bool owns_;
636 };
637
638 template<class Mutex>
639 void swap(shared_lock<Mutex>& lhs, shared_lock<Mutex>& rhs) noexcept
640 {
641 lhs.swap(rhs);
642 }
643
644 namespace aux
645 {
646 template<class L>
647 int try_lock_tail(int idx, L& l)
648 {
649 if (!l.try_lock())
650 return idx;
651 else
652 return -1;
653 }
654
655 template<class L1, class... L2>
656 int try_lock_tail(int idx, L1& l1, L2&... ls)
657 {
658 if (!l1.try_lock())
659 return idx;
660
661 auto ret = try_lock_tail(idx + 1, ls...);
662 if (ret != -1)
663 l1.unlock();
664
665 return ret;
666 }
667 }
668
669 template<class L1, class L2, class... L3>
670 int try_lock(L1& l1, L2& l2, L3&... ls)
671 {
672 return aux::try_lock_tail(0, l1, l2, ls...);
673 }
674
675 namespace aux
676 {
677 template<class L>
678 bool lock_tail(L& l)
679 {
680 return l.try_lock();
681 }
682
683 template<class L1, class... L2>
684 bool lock_tail(L1& l1, L2&... ls)
685 {
686 if (l1.try_lock())
687 {
688 auto ret = lock_tail(ls...);
689 if (ret)
690 return true;
691
692 l1.unlock();
693 }
694
695 return false;
696 }
697 }
698
699 template<class L1, class L2, class... L3>
700 void lock(L1& l1, L2& l2, L3&... ls)
701 {
702 do
703 {
704 l1.lock();
705
706 if (aux::lock_tail(l2, ls...))
707 return;
708 l1.unlock();
709 } while (true);
710 }
711
712 struct once_flag
713 {
714 constexpr once_flag() noexcept;
715
716 once_flag(const once_flag&) = delete;
717 once_flag& operator=(const once_flag&) = delete;
718 };
719
720 template<class Callable, class... Args>
721 void call_once(once_flag& flag, Callable&& func, Args&&... args);
722}
723
724#endif
Note: See TracBrowser for help on using the repository browser.