1 | // -*- C++ -*- |
2 | //===----------------------------------------------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef _LIBCPP_MUTEX |
11 | #define _LIBCPP_MUTEX |
12 | |
13 | /* |
14 | mutex synopsis |
15 | |
16 | namespace std |
17 | { |
18 | |
19 | class mutex |
20 | { |
21 | public: |
22 | constexpr mutex() noexcept; |
23 | ~mutex(); |
24 | |
25 | mutex(const mutex&) = delete; |
26 | mutex& operator=(const mutex&) = delete; |
27 | |
28 | void lock(); |
29 | bool try_lock(); |
30 | void unlock(); |
31 | |
32 | typedef pthread_mutex_t* native_handle_type; |
33 | native_handle_type native_handle(); |
34 | }; |
35 | |
36 | class recursive_mutex |
37 | { |
38 | public: |
39 | recursive_mutex(); |
40 | ~recursive_mutex(); |
41 | |
42 | recursive_mutex(const recursive_mutex&) = delete; |
43 | recursive_mutex& operator=(const recursive_mutex&) = delete; |
44 | |
45 | void lock(); |
46 | bool try_lock() noexcept; |
47 | void unlock(); |
48 | |
49 | typedef pthread_mutex_t* native_handle_type; |
50 | native_handle_type native_handle(); |
51 | }; |
52 | |
53 | class timed_mutex |
54 | { |
55 | public: |
56 | timed_mutex(); |
57 | ~timed_mutex(); |
58 | |
59 | timed_mutex(const timed_mutex&) = delete; |
60 | timed_mutex& operator=(const timed_mutex&) = delete; |
61 | |
62 | void lock(); |
63 | bool try_lock(); |
64 | template <class Rep, class Period> |
65 | bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); |
66 | template <class Clock, class Duration> |
67 | bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); |
68 | void unlock(); |
69 | }; |
70 | |
71 | class recursive_timed_mutex |
72 | { |
73 | public: |
74 | recursive_timed_mutex(); |
75 | ~recursive_timed_mutex(); |
76 | |
77 | recursive_timed_mutex(const recursive_timed_mutex&) = delete; |
78 | recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; |
79 | |
80 | void lock(); |
81 | bool try_lock() noexcept; |
82 | template <class Rep, class Period> |
83 | bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); |
84 | template <class Clock, class Duration> |
85 | bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); |
86 | void unlock(); |
87 | }; |
88 | |
89 | struct defer_lock_t { explicit defer_lock_t() = default; }; |
90 | struct try_to_lock_t { explicit try_to_lock_t() = default; }; |
91 | struct adopt_lock_t { explicit adopt_lock_t() = default; }; |
92 | |
93 | inline constexpr defer_lock_t defer_lock{}; |
94 | inline constexpr try_to_lock_t try_to_lock{}; |
95 | inline constexpr adopt_lock_t adopt_lock{}; |
96 | |
97 | template <class Mutex> |
98 | class lock_guard |
99 | { |
100 | public: |
101 | typedef Mutex mutex_type; |
102 | |
103 | explicit lock_guard(mutex_type& m); |
104 | lock_guard(mutex_type& m, adopt_lock_t); |
105 | ~lock_guard(); |
106 | |
107 | lock_guard(lock_guard const&) = delete; |
108 | lock_guard& operator=(lock_guard const&) = delete; |
109 | }; |
110 | |
111 | template <class... MutexTypes> |
112 | class scoped_lock // C++17 |
113 | { |
114 | public: |
115 | using mutex_type = Mutex; // Only if sizeof...(MutexTypes) == 1 |
116 | |
117 | explicit scoped_lock(MutexTypes&... m); |
118 | scoped_lock(adopt_lock_t, MutexTypes&... m); |
119 | ~scoped_lock(); |
120 | scoped_lock(scoped_lock const&) = delete; |
121 | scoped_lock& operator=(scoped_lock const&) = delete; |
122 | private: |
123 | tuple<MutexTypes&...> pm; // exposition only |
124 | }; |
125 | |
126 | template <class Mutex> |
127 | class unique_lock |
128 | { |
129 | public: |
130 | typedef Mutex mutex_type; |
131 | unique_lock() noexcept; |
132 | explicit unique_lock(mutex_type& m); |
133 | unique_lock(mutex_type& m, defer_lock_t) noexcept; |
134 | unique_lock(mutex_type& m, try_to_lock_t); |
135 | unique_lock(mutex_type& m, adopt_lock_t); |
136 | template <class Clock, class Duration> |
137 | unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time); |
138 | template <class Rep, class Period> |
139 | unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time); |
140 | ~unique_lock(); |
141 | |
142 | unique_lock(unique_lock const&) = delete; |
143 | unique_lock& operator=(unique_lock const&) = delete; |
144 | |
145 | unique_lock(unique_lock&& u) noexcept; |
146 | unique_lock& operator=(unique_lock&& u) noexcept; |
147 | |
148 | void lock(); |
149 | bool try_lock(); |
150 | |
151 | template <class Rep, class Period> |
152 | bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); |
153 | template <class Clock, class Duration> |
154 | bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); |
155 | |
156 | void unlock(); |
157 | |
158 | void swap(unique_lock& u) noexcept; |
159 | mutex_type* release() noexcept; |
160 | |
161 | bool owns_lock() const noexcept; |
162 | explicit operator bool () const noexcept; |
163 | mutex_type* mutex() const noexcept; |
164 | }; |
165 | |
166 | template <class Mutex> |
167 | void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept; |
168 | |
169 | template <class L1, class L2, class... L3> |
170 | int try_lock(L1&, L2&, L3&...); |
171 | template <class L1, class L2, class... L3> |
172 | void lock(L1&, L2&, L3&...); |
173 | |
174 | struct once_flag |
175 | { |
176 | constexpr once_flag() noexcept; |
177 | |
178 | once_flag(const once_flag&) = delete; |
179 | once_flag& operator=(const once_flag&) = delete; |
180 | }; |
181 | |
182 | template<class Callable, class ...Args> |
183 | void call_once(once_flag& flag, Callable&& func, Args&&... args); |
184 | |
185 | } // std |
186 | |
187 | */ |
188 | |
189 | #if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) |
190 | # include <__cxx03/mutex> |
191 | #else |
192 | # include <__chrono/steady_clock.h> |
193 | # include <__chrono/time_point.h> |
194 | # include <__condition_variable/condition_variable.h> |
195 | # include <__config> |
196 | # include <__mutex/lock_guard.h> |
197 | # include <__mutex/mutex.h> |
198 | # include <__mutex/once_flag.h> |
199 | # include <__mutex/tag_types.h> |
200 | # include <__mutex/unique_lock.h> |
201 | # include <__thread/id.h> |
202 | # include <__thread/support.h> |
203 | # include <__utility/forward.h> |
204 | # include <limits> |
205 | # ifndef _LIBCPP_CXX03_LANG |
206 | # include <tuple> |
207 | # endif |
208 | # include <version> |
209 | |
210 | # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
211 | # pragma GCC system_header |
212 | # endif |
213 | |
214 | _LIBCPP_PUSH_MACROS |
215 | # include <__undef_macros> |
216 | |
217 | _LIBCPP_BEGIN_NAMESPACE_STD |
218 | |
219 | # if _LIBCPP_HAS_THREADS |
220 | |
221 | class _LIBCPP_EXPORTED_FROM_ABI recursive_mutex { |
222 | __libcpp_recursive_mutex_t __m_; |
223 | |
224 | public: |
225 | recursive_mutex(); |
226 | ~recursive_mutex(); |
227 | |
228 | recursive_mutex(const recursive_mutex&) = delete; |
229 | recursive_mutex& operator=(const recursive_mutex&) = delete; |
230 | |
231 | void lock(); |
232 | bool try_lock() _NOEXCEPT; |
233 | void unlock() _NOEXCEPT; |
234 | |
235 | typedef __libcpp_recursive_mutex_t* native_handle_type; |
236 | |
237 | _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; } |
238 | }; |
239 | |
240 | class _LIBCPP_EXPORTED_FROM_ABI timed_mutex { |
241 | mutex __m_; |
242 | condition_variable __cv_; |
243 | bool __locked_; |
244 | |
245 | public: |
246 | timed_mutex(); |
247 | ~timed_mutex(); |
248 | |
249 | timed_mutex(const timed_mutex&) = delete; |
250 | timed_mutex& operator=(const timed_mutex&) = delete; |
251 | |
252 | public: |
253 | void lock(); |
254 | bool try_lock() _NOEXCEPT; |
255 | template <class _Rep, class _Period> |
256 | _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) { |
257 | return try_lock_until(chrono::steady_clock::now() + __d); |
258 | } |
259 | |
260 | template <class _Clock, class _Duration> |
261 | _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { |
262 | using namespace chrono; |
263 | unique_lock<mutex> __lk(__m_); |
264 | bool __no_timeout = _Clock::now() < __t; |
265 | while (__no_timeout && __locked_) |
266 | __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout; |
267 | if (!__locked_) { |
268 | __locked_ = true; |
269 | return true; |
270 | } |
271 | return false; |
272 | } |
273 | |
274 | void unlock() _NOEXCEPT; |
275 | }; |
276 | |
277 | class _LIBCPP_EXPORTED_FROM_ABI recursive_timed_mutex { |
278 | mutex __m_; |
279 | condition_variable __cv_; |
280 | size_t __count_; |
281 | __thread_id __id_; |
282 | |
283 | public: |
284 | recursive_timed_mutex(); |
285 | ~recursive_timed_mutex(); |
286 | |
287 | recursive_timed_mutex(const recursive_timed_mutex&) = delete; |
288 | recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; |
289 | |
290 | void lock(); |
291 | bool try_lock() _NOEXCEPT; |
292 | template <class _Rep, class _Period> |
293 | _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) { |
294 | return try_lock_until(chrono::steady_clock::now() + __d); |
295 | } |
296 | |
297 | template <class _Clock, class _Duration> |
298 | _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { |
299 | using namespace chrono; |
300 | __thread_id __id = this_thread::get_id(); |
301 | unique_lock<mutex> __lk(__m_); |
302 | if (__id == __id_) { |
303 | if (__count_ == numeric_limits<size_t>::max()) |
304 | return false; |
305 | ++__count_; |
306 | return true; |
307 | } |
308 | bool __no_timeout = _Clock::now() < __t; |
309 | while (__no_timeout && __count_ != 0) |
310 | __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout; |
311 | if (__count_ == 0) { |
312 | __count_ = 1; |
313 | __id_ = __id; |
314 | return true; |
315 | } |
316 | return false; |
317 | } |
318 | |
319 | void unlock() _NOEXCEPT; |
320 | }; |
321 | |
322 | template <class _L0, class _L1> |
323 | _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) { |
324 | unique_lock<_L0> __u0(__l0, try_to_lock_t()); |
325 | if (__u0.owns_lock()) { |
326 | if (__l1.try_lock()) { |
327 | __u0.release(); |
328 | return -1; |
329 | } else |
330 | return 1; |
331 | } |
332 | return 0; |
333 | } |
334 | |
335 | # ifndef _LIBCPP_CXX03_LANG |
336 | |
337 | template <class _L0, class _L1, class _L2, class... _L3> |
338 | _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { |
339 | int __r = 0; |
340 | unique_lock<_L0> __u0(__l0, try_to_lock); |
341 | if (__u0.owns_lock()) { |
342 | __r = std::try_lock(__l1, __l2, __l3...); |
343 | if (__r == -1) |
344 | __u0.release(); |
345 | else |
346 | ++__r; |
347 | } |
348 | return __r; |
349 | } |
350 | |
351 | # endif // _LIBCPP_CXX03_LANG |
352 | |
353 | template <class _L0, class _L1> |
354 | _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) { |
355 | while (true) { |
356 | { |
357 | unique_lock<_L0> __u0(__l0); |
358 | if (__l1.try_lock()) { |
359 | __u0.release(); |
360 | break; |
361 | } |
362 | } |
363 | __libcpp_thread_yield(); |
364 | { |
365 | unique_lock<_L1> __u1(__l1); |
366 | if (__l0.try_lock()) { |
367 | __u1.release(); |
368 | break; |
369 | } |
370 | } |
371 | __libcpp_thread_yield(); |
372 | } |
373 | } |
374 | |
375 | # ifndef _LIBCPP_CXX03_LANG |
376 | |
377 | template <class _L0, class _L1, class _L2, class... _L3> |
378 | void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { |
379 | while (true) { |
380 | switch (__i) { |
381 | case 0: { |
382 | unique_lock<_L0> __u0(__l0); |
383 | __i = std::try_lock(__l1, __l2, __l3...); |
384 | if (__i == -1) { |
385 | __u0.release(); |
386 | return; |
387 | } |
388 | } |
389 | ++__i; |
390 | __libcpp_thread_yield(); |
391 | break; |
392 | case 1: { |
393 | unique_lock<_L1> __u1(__l1); |
394 | __i = std::try_lock(__l2, __l3..., __l0); |
395 | if (__i == -1) { |
396 | __u1.release(); |
397 | return; |
398 | } |
399 | } |
400 | if (__i == sizeof...(_L3) + 1) |
401 | __i = 0; |
402 | else |
403 | __i += 2; |
404 | __libcpp_thread_yield(); |
405 | break; |
406 | default: |
407 | std::__lock_first(__i - 2, __l2, __l3..., __l0, __l1); |
408 | return; |
409 | } |
410 | } |
411 | } |
412 | |
413 | template <class _L0, class _L1, class _L2, class... _L3> |
414 | inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { |
415 | std::__lock_first(0, __l0, __l1, __l2, __l3...); |
416 | } |
417 | |
418 | # endif // _LIBCPP_CXX03_LANG |
419 | |
420 | # if _LIBCPP_STD_VER >= 17 |
421 | template <class... _Mutexes> |
422 | class scoped_lock; |
423 | |
424 | template <> |
425 | class scoped_lock<> { |
426 | public: |
427 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock() {} |
428 | ~scoped_lock() = default; |
429 | |
430 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t) {} |
431 | |
432 | scoped_lock(scoped_lock const&) = delete; |
433 | scoped_lock& operator=(scoped_lock const&) = delete; |
434 | }; |
435 | |
436 | template <class _Mutex> |
437 | class _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) scoped_lock<_Mutex> { |
438 | public: |
439 | typedef _Mutex mutex_type; |
440 | |
441 | private: |
442 | mutex_type& __m_; |
443 | |
444 | public: |
445 | [[nodiscard]] |
446 | _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) |
447 | : __m_(__m) { |
448 | __m_.lock(); |
449 | } |
450 | |
451 | ~scoped_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) { __m_.unlock(); } |
452 | |
453 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t, mutex_type& __m) |
454 | _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m)) |
455 | : __m_(__m) {} |
456 | |
457 | scoped_lock(scoped_lock const&) = delete; |
458 | scoped_lock& operator=(scoped_lock const&) = delete; |
459 | }; |
460 | |
461 | template <class... _MArgs> |
462 | class scoped_lock { |
463 | static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required" ); |
464 | typedef tuple<_MArgs&...> _MutexTuple; |
465 | |
466 | public: |
467 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) : __t_(__margs...) { |
468 | std::lock(__margs...); |
469 | } |
470 | |
471 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs) : __t_(__margs...) {} |
472 | |
473 | _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { |
474 | typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices; |
475 | __unlock_unpack(_Indices{}, __t_); |
476 | } |
477 | |
478 | scoped_lock(scoped_lock const&) = delete; |
479 | scoped_lock& operator=(scoped_lock const&) = delete; |
480 | |
481 | private: |
482 | template <size_t... _Indx> |
483 | _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) { |
484 | (std::get<_Indx>(__mt).unlock(), ...); |
485 | } |
486 | |
487 | _MutexTuple __t_; |
488 | }; |
489 | _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock); |
490 | |
491 | # endif // _LIBCPP_STD_VER >= 17 |
492 | # endif // _LIBCPP_HAS_THREADS |
493 | |
494 | _LIBCPP_END_NAMESPACE_STD |
495 | |
496 | _LIBCPP_POP_MACROS |
497 | |
498 | # if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 |
499 | # include <atomic> |
500 | # include <concepts> |
501 | # include <cstdlib> |
502 | # include <cstring> |
503 | # include <ctime> |
504 | # include <initializer_list> |
505 | # include <iosfwd> |
506 | # include <new> |
507 | # include <optional> |
508 | # include <stdexcept> |
509 | # include <system_error> |
510 | # include <type_traits> |
511 | # include <typeinfo> |
512 | # endif |
513 | #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) |
514 | |
515 | #endif // _LIBCPP_MUTEX |
516 | |