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

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

cpp: changed mutex destructor to default to allow it to be placed in once_flag, implemented call_once

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