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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8e24583 was b251af5a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Remove <lib/cpp/include/bits/common.hpp>, which is no longer necessary

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