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

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

cpp: refactored the library layout, everything from the impl directory was moved to the bits directory for the sake of consistency, updated copyright notices and include guards

  • Property mode set to 100644
File size: 14.1 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_BITS_THREAD_MUTEX
30#define LIBCPP_BITS_THREAD_MUTEX
31
32#include <__bits/common.hpp>
33#include <__bits/thread/threading.hpp>
34#include <functional>
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 struct defer_lock_t
201 { /* DUMMY BODY */ };
202
203 struct try_to_lock_t
204 { /* DUMMY BODY */ };
205
206 struct adopt_lock_t
207 { /* DUMMY BODY */ };
208
209 constexpr defer_lock_t defer_lock
210 { /* DUMMY BODY */ };
211
212 constexpr try_to_lock_t try_to_lock
213 { /* DUMMY BODY */ };
214
215 constexpr adopt_lock_t adopt_lock
216 { /* DUMMY BODY */ };
217
218 /**
219 * 30.4.2.1, class template lock_guard:
220 */
221
222 template<class Mutex>
223 class lock_guard
224 {
225 public:
226 using mutex_type = Mutex;
227
228 explicit lock_guard(mutex_type& mtx)
229 : mtx_{mtx}
230 {
231 mtx.lock();
232 }
233
234 lock_guard(mutex_type& mtx, adopt_lock_t)
235 : mtx_{mtx}
236 { /* DUMMY BODY */ }
237
238 ~lock_guard()
239 {
240 mtx_.unlock();
241 }
242
243 lock_guard(const lock_guard&) = delete;
244 lock_guard& operator=(const lock_guard&) = delete;
245
246 private:
247 mutex_type& mtx_;
248 };
249
250 template<class Mutex>
251 class unique_lock
252 {
253 public:
254 using mutex_type = Mutex;
255
256 /**
257 * 30.4.2.2.1, construction/copy/destroy:
258 */
259
260 unique_lock() noexcept
261 : mtx_{nullptr}, owns_{false}
262 { /* DUMMY BODY */ }
263
264 explicit unique_lock(mutex_type& mtx)
265 : mtx_{&mtx}, owns_{true}
266 {
267 mtx_->lock();
268 }
269
270 unique_lock(mutex_type& mtx, defer_lock_t) noexcept
271 : mtx_{&mtx}, owns_{false}
272 { /* DUMMY BODY */ }
273
274 unique_lock(mutex_type& mtx, try_to_lock_t)
275 : mtx_{&mtx}, owns_{}
276 {
277 owns_ = mtx_->try_lock();
278 }
279
280 unique_lock(mutex_type& mtx, adopt_lock_t)
281 : mtx_{&mtx}, owns_{true}
282 { /* DUMMY BODY */ }
283
284 template<class Clock, class Duration>
285 unique_lock(mutex_type& mtx, const chrono::time_point<Clock, Duration>& abs_time)
286 : mtx_{&mtx}, owns_{}
287 {
288 owns_ = mtx_->try_lock_until(abs_time);
289 }
290
291 template<class Rep, class Period>
292 unique_lock(mutex_type& mtx, const chrono::duration<Rep, Period>& rel_time)
293 : mtx_{&mtx}, owns_{}
294 {
295 owns_ = mtx_->try_lock_for(rel_time);
296 }
297
298 ~unique_lock()
299 {
300 if (owns_)
301 mtx_->unlock();
302 }
303
304 unique_lock(const unique_lock&) = delete;
305 unique_lock& operator=(const unique_lock&) = delete;
306
307 unique_lock(unique_lock&& other) noexcept
308 : mtx_{move(other.mtx_)}, owns_{move(other.owns_)}
309 {
310 other.mtx_ = nullptr;
311 other.owns_ = false;
312 }
313
314 unique_lock& operator=(unique_lock&& other)
315 {
316 if (owns_)
317 mtx_->unlock();
318
319 mtx_ = move(other.mtx_);
320 owns_ = move(other.owns_);
321
322 other.mtx_ = nullptr;
323 other.owns_ = false;
324 }
325
326 /**
327 * 30.4.2.2.2, locking:
328 */
329
330 void lock()
331 {
332 /**
333 * TODO:
334 * throw system_error operation_not_permitted if mtx_ == nullptr
335 * throw system_error resource_deadlock_would_occur if owns_ == true
336 */
337
338 mtx_->lock();
339 owns_ = true;
340 }
341
342 bool try_lock()
343 {
344 /**
345 * TODO:
346 * throw system_error operation_not_permitted if mtx_ == nullptr
347 * throw system_error resource_deadlock_would_occur if owns_ == true
348 */
349
350 owns_ = mtx_->try_lock();
351
352 return owns_;
353 }
354
355 template<class Rep, class Period>
356 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
357 {
358 /**
359 * TODO:
360 * throw system_error operation_not_permitted if mtx_ == nullptr
361 * throw system_error resource_deadlock_would_occur if owns_ == true
362 */
363
364 owns_ = mtx_->try_lock_for(rel_time);
365
366 return owns_;
367 }
368
369 template<class Clock, class Duration>
370 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
371 {
372 /**
373 * TODO:
374 * throw system_error operation_not_permitted if mtx_ == nullptr
375 * throw system_error resource_deadlock_would_occur if owns_ == true
376 */
377
378 owns_ = mtx_->try_lock_until(abs_time);
379
380 return owns_;
381 }
382
383 void unlock()
384 {
385 /**
386 * TODO:
387 * throw system_error operation_not_permitted if owns_ == false
388 */
389
390 mtx_->unlock();
391 }
392
393 /**
394 * 30.4.2.2.3, modifiers:
395 */
396
397 void swap(unique_lock& other) noexcept
398 {
399 std::swap(mtx_, other.mtx_);
400 std::swap(owns_, other.owns_);
401 }
402
403 mutex_type* release() noexcept
404 {
405 auto ret = mtx_;
406 mtx_ = nullptr;
407 owns_ = false;
408
409 return ret;
410 }
411
412 /**
413 * 30.4.2.2.4, observers:
414 */
415
416 bool owns_lock() const noexcept
417 {
418 return owns_;
419 }
420
421 explicit operator bool() const noexcept
422 {
423 return owns_;
424 }
425
426 mutex_type* mutex() const noexcept
427 {
428 return mtx_;
429 }
430
431 private:
432 mutex_type* mtx_;
433 bool owns_;
434 };
435
436 template<class Mutex>
437 void swap(unique_lock<Mutex>& lhs, unique_lock<Mutex>& rhs) noexcept
438 {
439 lhs.swap(rhs);
440 }
441
442 namespace aux
443 {
444 template<class L>
445 int try_lock_tail(int idx, L& l)
446 {
447 if (!l.try_lock())
448 return idx;
449 else
450 return -1;
451 }
452
453 template<class L1, class... L2>
454 int try_lock_tail(int idx, L1& l1, L2&... ls)
455 {
456 if (!l1.try_lock())
457 return idx;
458
459 auto ret = try_lock_tail(idx + 1, ls...);
460 if (ret != -1)
461 l1.unlock();
462
463 return ret;
464 }
465 }
466
467 template<class L1, class L2, class... L3>
468 int try_lock(L1& l1, L2& l2, L3&... ls)
469 {
470 return aux::try_lock_tail(0, l1, l2, ls...);
471 }
472
473 namespace aux
474 {
475 template<class L>
476 bool lock_tail(L& l)
477 {
478 return l.try_lock();
479 }
480
481 template<class L1, class... L2>
482 bool lock_tail(L1& l1, L2&... ls)
483 {
484 if (l1.try_lock())
485 {
486 auto ret = lock_tail(ls...);
487 if (ret)
488 return true;
489
490 l1.unlock();
491 }
492
493 return false;
494 }
495 }
496
497 template<class L1, class L2, class... L3>
498 void lock(L1& l1, L2& l2, L3&... ls)
499 {
500 do
501 {
502 l1.lock();
503
504 if (aux::lock_tail(l2, ls...))
505 return;
506 l1.unlock();
507 } while (true);
508 }
509
510 struct once_flag
511 {
512 constexpr once_flag() noexcept
513 : called_{false}, mtx_{}
514 { /* DUMMY BODY */ }
515
516 once_flag(const once_flag&) = delete;
517 once_flag& operator=(const once_flag&) = delete;
518
519 private:
520 bool called_;
521 mutex mtx_;
522
523 template<class Callable, class... Args>
524 friend void call_once(once_flag&, Callable&&, Args&&...);
525 };
526
527 template<class Callable, class... Args>
528 void call_once(once_flag& flag, Callable&& func, Args&&... args)
529 {
530 flag.mtx_.lock();
531 if (!flag.called_)
532 {
533 // TODO: exception handling
534
535 aux::INVOKE(forward<Callable>(func), forward<Args>(args)...);
536 flag.called_ = true;
537 }
538 flag.mtx_.unlock();
539 }
540}
541
542#endif
Note: See TracBrowser for help on using the repository browser.