/src/llvm-project-18.1.8.build/include/c++/v1/mutex
Line | Count | Source (jump to first uncovered line) |
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 | | #include <__assert> // all public C++ headers provide the assertion handler |
190 | | #include <__chrono/steady_clock.h> |
191 | | #include <__chrono/time_point.h> |
192 | | #include <__condition_variable/condition_variable.h> |
193 | | #include <__config> |
194 | | #include <__memory/shared_ptr.h> |
195 | | #include <__mutex/lock_guard.h> |
196 | | #include <__mutex/mutex.h> |
197 | | #include <__mutex/once_flag.h> |
198 | | #include <__mutex/tag_types.h> |
199 | | #include <__mutex/unique_lock.h> |
200 | | #include <__thread/id.h> |
201 | | #include <__threading_support> |
202 | | #include <__utility/forward.h> |
203 | | #include <cstddef> |
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 | | #ifndef _LIBCPP_HAS_NO_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 | 0 | _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 | | template <class _Clock, class _Duration> |
260 | | _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool |
261 | | try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); |
262 | | void unlock() _NOEXCEPT; |
263 | | }; |
264 | | |
265 | | template <class _Clock, class _Duration> |
266 | | bool timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { |
267 | | using namespace chrono; |
268 | | unique_lock<mutex> __lk(__m_); |
269 | | bool __no_timeout = _Clock::now() < __t; |
270 | | while (__no_timeout && __locked_) |
271 | | __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout; |
272 | | if (!__locked_) { |
273 | | __locked_ = true; |
274 | | return true; |
275 | | } |
276 | | return false; |
277 | | } |
278 | | |
279 | | class _LIBCPP_EXPORTED_FROM_ABI recursive_timed_mutex { |
280 | | mutex __m_; |
281 | | condition_variable __cv_; |
282 | | size_t __count_; |
283 | | __thread_id __id_; |
284 | | |
285 | | public: |
286 | | recursive_timed_mutex(); |
287 | | ~recursive_timed_mutex(); |
288 | | |
289 | | recursive_timed_mutex(const recursive_timed_mutex&) = delete; |
290 | | recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; |
291 | | |
292 | | void lock(); |
293 | | bool try_lock() _NOEXCEPT; |
294 | | template <class _Rep, class _Period> |
295 | | _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) { |
296 | | return try_lock_until(chrono::steady_clock::now() + __d); |
297 | | } |
298 | | template <class _Clock, class _Duration> |
299 | | _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool |
300 | | try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); |
301 | | void unlock() _NOEXCEPT; |
302 | | }; |
303 | | |
304 | | template <class _Clock, class _Duration> |
305 | | bool recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { |
306 | | using namespace chrono; |
307 | | __thread_id __id = this_thread::get_id(); |
308 | | unique_lock<mutex> __lk(__m_); |
309 | | if (__id == __id_) { |
310 | | if (__count_ == numeric_limits<size_t>::max()) |
311 | | return false; |
312 | | ++__count_; |
313 | | return true; |
314 | | } |
315 | | bool __no_timeout = _Clock::now() < __t; |
316 | | while (__no_timeout && __count_ != 0) |
317 | | __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout; |
318 | | if (__count_ == 0) { |
319 | | __count_ = 1; |
320 | | __id_ = __id; |
321 | | return true; |
322 | | } |
323 | | return false; |
324 | | } |
325 | | |
326 | | template <class _L0, class _L1> |
327 | | _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) { |
328 | | unique_lock<_L0> __u0(__l0, try_to_lock_t()); |
329 | | if (__u0.owns_lock()) { |
330 | | if (__l1.try_lock()) { |
331 | | __u0.release(); |
332 | | return -1; |
333 | | } else |
334 | | return 1; |
335 | | } |
336 | | return 0; |
337 | | } |
338 | | |
339 | | # ifndef _LIBCPP_CXX03_LANG |
340 | | |
341 | | template <class _L0, class _L1, class _L2, class... _L3> |
342 | | _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { |
343 | | int __r = 0; |
344 | | unique_lock<_L0> __u0(__l0, try_to_lock); |
345 | | if (__u0.owns_lock()) { |
346 | | __r = std::try_lock(__l1, __l2, __l3...); |
347 | | if (__r == -1) |
348 | | __u0.release(); |
349 | | else |
350 | | ++__r; |
351 | | } |
352 | | return __r; |
353 | | } |
354 | | |
355 | | # endif // _LIBCPP_CXX03_LANG |
356 | | |
357 | | template <class _L0, class _L1> |
358 | | _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) { |
359 | | while (true) { |
360 | | { |
361 | | unique_lock<_L0> __u0(__l0); |
362 | | if (__l1.try_lock()) { |
363 | | __u0.release(); |
364 | | break; |
365 | | } |
366 | | } |
367 | | __libcpp_thread_yield(); |
368 | | { |
369 | | unique_lock<_L1> __u1(__l1); |
370 | | if (__l0.try_lock()) { |
371 | | __u1.release(); |
372 | | break; |
373 | | } |
374 | | } |
375 | | __libcpp_thread_yield(); |
376 | | } |
377 | | } |
378 | | |
379 | | # ifndef _LIBCPP_CXX03_LANG |
380 | | |
381 | | template <class _L0, class _L1, class _L2, class... _L3> |
382 | | void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { |
383 | | while (true) { |
384 | | switch (__i) { |
385 | | case 0: { |
386 | | unique_lock<_L0> __u0(__l0); |
387 | | __i = std::try_lock(__l1, __l2, __l3...); |
388 | | if (__i == -1) { |
389 | | __u0.release(); |
390 | | return; |
391 | | } |
392 | | } |
393 | | ++__i; |
394 | | __libcpp_thread_yield(); |
395 | | break; |
396 | | case 1: { |
397 | | unique_lock<_L1> __u1(__l1); |
398 | | __i = std::try_lock(__l2, __l3..., __l0); |
399 | | if (__i == -1) { |
400 | | __u1.release(); |
401 | | return; |
402 | | } |
403 | | } |
404 | | if (__i == sizeof...(_L3) + 1) |
405 | | __i = 0; |
406 | | else |
407 | | __i += 2; |
408 | | __libcpp_thread_yield(); |
409 | | break; |
410 | | default: |
411 | | std::__lock_first(__i - 2, __l2, __l3..., __l0, __l1); |
412 | | return; |
413 | | } |
414 | | } |
415 | | } |
416 | | |
417 | | template <class _L0, class _L1, class _L2, class... _L3> |
418 | | inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { |
419 | | std::__lock_first(0, __l0, __l1, __l2, __l3...); |
420 | | } |
421 | | |
422 | | template <class _L0> |
423 | | inline _LIBCPP_HIDE_FROM_ABI void __unlock(_L0& __l0) { |
424 | | __l0.unlock(); |
425 | | } |
426 | | |
427 | | template <class _L0, class _L1> |
428 | | inline _LIBCPP_HIDE_FROM_ABI void __unlock(_L0& __l0, _L1& __l1) { |
429 | | __l0.unlock(); |
430 | | __l1.unlock(); |
431 | | } |
432 | | |
433 | | template <class _L0, class _L1, class _L2, class... _L3> |
434 | | inline _LIBCPP_HIDE_FROM_ABI void __unlock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { |
435 | | __l0.unlock(); |
436 | | __l1.unlock(); |
437 | | std::__unlock(__l2, __l3...); |
438 | | } |
439 | | |
440 | | # endif // _LIBCPP_CXX03_LANG |
441 | | |
442 | | # if _LIBCPP_STD_VER >= 17 |
443 | | template <class... _Mutexes> |
444 | | class _LIBCPP_TEMPLATE_VIS scoped_lock; |
445 | | |
446 | | template <> |
447 | | class _LIBCPP_TEMPLATE_VIS scoped_lock<> { |
448 | | public: |
449 | 0 | explicit scoped_lock() {} |
450 | | ~scoped_lock() = default; |
451 | | |
452 | 0 | _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t) {} |
453 | | |
454 | | scoped_lock(scoped_lock const&) = delete; |
455 | | scoped_lock& operator=(scoped_lock const&) = delete; |
456 | | }; |
457 | | |
458 | | template <class _Mutex> |
459 | | class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) scoped_lock<_Mutex> { |
460 | | public: |
461 | | typedef _Mutex mutex_type; |
462 | | |
463 | | private: |
464 | | mutex_type& __m_; |
465 | | |
466 | | public: |
467 | | explicit scoped_lock(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) : __m_(__m) { |
468 | | __m_.lock(); |
469 | | } |
470 | | |
471 | | ~scoped_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) { __m_.unlock(); } |
472 | | |
473 | | _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t, mutex_type& __m) |
474 | | _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m)) |
475 | | : __m_(__m) {} |
476 | | |
477 | | scoped_lock(scoped_lock const&) = delete; |
478 | | scoped_lock& operator=(scoped_lock const&) = delete; |
479 | | }; |
480 | | |
481 | | template <class... _MArgs> |
482 | | class _LIBCPP_TEMPLATE_VIS scoped_lock { |
483 | | static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required"); |
484 | | typedef tuple<_MArgs&...> _MutexTuple; |
485 | | |
486 | | public: |
487 | | _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) : __t_(__margs...) { std::lock(__margs...); } |
488 | | |
489 | | _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs) : __t_(__margs...) {} |
490 | | |
491 | | _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { |
492 | | typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices; |
493 | | __unlock_unpack(_Indices{}, __t_); |
494 | | } |
495 | | |
496 | | scoped_lock(scoped_lock const&) = delete; |
497 | | scoped_lock& operator=(scoped_lock const&) = delete; |
498 | | |
499 | | private: |
500 | | template <size_t... _Indx> |
501 | | _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) { |
502 | | std::__unlock(std::get<_Indx>(__mt)...); |
503 | | } |
504 | | |
505 | | _MutexTuple __t_; |
506 | | }; |
507 | | _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock); |
508 | | |
509 | | # endif // _LIBCPP_STD_VER >= 17 |
510 | | #endif // !_LIBCPP_HAS_NO_THREADS |
511 | | |
512 | | _LIBCPP_END_NAMESPACE_STD |
513 | | |
514 | | _LIBCPP_POP_MACROS |
515 | | |
516 | | #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 |
517 | | # include <atomic> |
518 | | # include <concepts> |
519 | | # include <cstdlib> |
520 | | # include <cstring> |
521 | | # include <ctime> |
522 | | # include <initializer_list> |
523 | | # include <iosfwd> |
524 | | # include <new> |
525 | | # include <stdexcept> |
526 | | # include <system_error> |
527 | | # include <type_traits> |
528 | | # include <typeinfo> |
529 | | #endif |
530 | | |
531 | | #endif // _LIBCPP_MUTEX |