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 <__chrono/steady_clock.h> |
190 | #include <__chrono/time_point.h> |
191 | #include <__condition_variable/condition_variable.h> |
192 | #include <__config> |
193 | #include <__memory/shared_ptr.h> |
194 | #include <__mutex/lock_guard.h> |
195 | #include <__mutex/mutex.h> |
196 | #include <__mutex/once_flag.h> |
197 | #include <__mutex/tag_types.h> |
198 | #include <__mutex/unique_lock.h> |
199 | #include <__thread/id.h> |
200 | #include <__thread/support.h> |
201 | #include <__utility/forward.h> |
202 | #include <cstddef> |
203 | #include <limits> |
204 | #ifndef _LIBCPP_CXX03_LANG |
205 | # include <tuple> |
206 | #endif |
207 | #include <version> |
208 | |
209 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
210 | # pragma GCC system_header |
211 | #endif |
212 | |
213 | _LIBCPP_PUSH_MACROS |
214 | #include <__undef_macros> |
215 | |
216 | _LIBCPP_BEGIN_NAMESPACE_STD |
217 | |
218 | #ifndef _LIBCPP_HAS_NO_THREADS |
219 | |
220 | class _LIBCPP_EXPORTED_FROM_ABI recursive_mutex { |
221 | __libcpp_recursive_mutex_t __m_; |
222 | |
223 | public: |
224 | recursive_mutex(); |
225 | ~recursive_mutex(); |
226 | |
227 | recursive_mutex(const recursive_mutex&) = delete; |
228 | recursive_mutex& operator=(const recursive_mutex&) = delete; |
229 | |
230 | void lock(); |
231 | bool try_lock() _NOEXCEPT; |
232 | void unlock() _NOEXCEPT; |
233 | |
234 | typedef __libcpp_recursive_mutex_t* native_handle_type; |
235 | |
236 | _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; } |
237 | }; |
238 | |
239 | class _LIBCPP_EXPORTED_FROM_ABI timed_mutex { |
240 | mutex __m_; |
241 | condition_variable __cv_; |
242 | bool __locked_; |
243 | |
244 | public: |
245 | timed_mutex(); |
246 | ~timed_mutex(); |
247 | |
248 | timed_mutex(const timed_mutex&) = delete; |
249 | timed_mutex& operator=(const timed_mutex&) = delete; |
250 | |
251 | public: |
252 | void lock(); |
253 | bool try_lock() _NOEXCEPT; |
254 | template <class _Rep, class _Period> |
255 | _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) { |
256 | return try_lock_until(chrono::steady_clock::now() + __d); |
257 | } |
258 | template <class _Clock, class _Duration> |
259 | _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool |
260 | try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); |
261 | void unlock() _NOEXCEPT; |
262 | }; |
263 | |
264 | template <class _Clock, class _Duration> |
265 | bool timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { |
266 | using namespace chrono; |
267 | unique_lock<mutex> __lk(__m_); |
268 | bool __no_timeout = _Clock::now() < __t; |
269 | while (__no_timeout && __locked_) |
270 | __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout; |
271 | if (!__locked_) { |
272 | __locked_ = true; |
273 | return true; |
274 | } |
275 | return false; |
276 | } |
277 | |
278 | class _LIBCPP_EXPORTED_FROM_ABI recursive_timed_mutex { |
279 | mutex __m_; |
280 | condition_variable __cv_; |
281 | size_t __count_; |
282 | __thread_id __id_; |
283 | |
284 | public: |
285 | recursive_timed_mutex(); |
286 | ~recursive_timed_mutex(); |
287 | |
288 | recursive_timed_mutex(const recursive_timed_mutex&) = delete; |
289 | recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; |
290 | |
291 | void lock(); |
292 | bool try_lock() _NOEXCEPT; |
293 | template <class _Rep, class _Period> |
294 | _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) { |
295 | return try_lock_until(chrono::steady_clock::now() + __d); |
296 | } |
297 | template <class _Clock, class _Duration> |
298 | _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool |
299 | try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); |
300 | void unlock() _NOEXCEPT; |
301 | }; |
302 | |
303 | template <class _Clock, class _Duration> |
304 | bool recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { |
305 | using namespace chrono; |
306 | __thread_id __id = this_thread::get_id(); |
307 | unique_lock<mutex> __lk(__m_); |
308 | if (__id == __id_) { |
309 | if (__count_ == numeric_limits<size_t>::max()) |
310 | return false; |
311 | ++__count_; |
312 | return true; |
313 | } |
314 | bool __no_timeout = _Clock::now() < __t; |
315 | while (__no_timeout && __count_ != 0) |
316 | __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout; |
317 | if (__count_ == 0) { |
318 | __count_ = 1; |
319 | __id_ = __id; |
320 | return true; |
321 | } |
322 | return false; |
323 | } |
324 | |
325 | template <class _L0, class _L1> |
326 | _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) { |
327 | unique_lock<_L0> __u0(__l0, try_to_lock_t()); |
328 | if (__u0.owns_lock()) { |
329 | if (__l1.try_lock()) { |
330 | __u0.release(); |
331 | return -1; |
332 | } else |
333 | return 1; |
334 | } |
335 | return 0; |
336 | } |
337 | |
338 | # ifndef _LIBCPP_CXX03_LANG |
339 | |
340 | template <class _L0, class _L1, class _L2, class... _L3> |
341 | _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { |
342 | int __r = 0; |
343 | unique_lock<_L0> __u0(__l0, try_to_lock); |
344 | if (__u0.owns_lock()) { |
345 | __r = std::try_lock(__l1, __l2, __l3...); |
346 | if (__r == -1) |
347 | __u0.release(); |
348 | else |
349 | ++__r; |
350 | } |
351 | return __r; |
352 | } |
353 | |
354 | # endif // _LIBCPP_CXX03_LANG |
355 | |
356 | template <class _L0, class _L1> |
357 | _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) { |
358 | while (true) { |
359 | { |
360 | unique_lock<_L0> __u0(__l0); |
361 | if (__l1.try_lock()) { |
362 | __u0.release(); |
363 | break; |
364 | } |
365 | } |
366 | __libcpp_thread_yield(); |
367 | { |
368 | unique_lock<_L1> __u1(__l1); |
369 | if (__l0.try_lock()) { |
370 | __u1.release(); |
371 | break; |
372 | } |
373 | } |
374 | __libcpp_thread_yield(); |
375 | } |
376 | } |
377 | |
378 | # ifndef _LIBCPP_CXX03_LANG |
379 | |
380 | template <class _L0, class _L1, class _L2, class... _L3> |
381 | void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { |
382 | while (true) { |
383 | switch (__i) { |
384 | case 0: { |
385 | unique_lock<_L0> __u0(__l0); |
386 | __i = std::try_lock(__l1, __l2, __l3...); |
387 | if (__i == -1) { |
388 | __u0.release(); |
389 | return; |
390 | } |
391 | } |
392 | ++__i; |
393 | __libcpp_thread_yield(); |
394 | break; |
395 | case 1: { |
396 | unique_lock<_L1> __u1(__l1); |
397 | __i = std::try_lock(__l2, __l3..., __l0); |
398 | if (__i == -1) { |
399 | __u1.release(); |
400 | return; |
401 | } |
402 | } |
403 | if (__i == sizeof...(_L3) + 1) |
404 | __i = 0; |
405 | else |
406 | __i += 2; |
407 | __libcpp_thread_yield(); |
408 | break; |
409 | default: |
410 | std::__lock_first(__i - 2, __l2, __l3..., __l0, __l1); |
411 | return; |
412 | } |
413 | } |
414 | } |
415 | |
416 | template <class _L0, class _L1, class _L2, class... _L3> |
417 | inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { |
418 | std::__lock_first(0, __l0, __l1, __l2, __l3...); |
419 | } |
420 | |
421 | # endif // _LIBCPP_CXX03_LANG |
422 | |
423 | # if _LIBCPP_STD_VER >= 17 |
424 | template <class... _Mutexes> |
425 | class _LIBCPP_TEMPLATE_VIS scoped_lock; |
426 | |
427 | template <> |
428 | class _LIBCPP_TEMPLATE_VIS scoped_lock<> { |
429 | public: |
430 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock() {} |
431 | ~scoped_lock() = default; |
432 | |
433 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t) {} |
434 | |
435 | scoped_lock(scoped_lock const&) = delete; |
436 | scoped_lock& operator=(scoped_lock const&) = delete; |
437 | }; |
438 | |
439 | template <class _Mutex> |
440 | class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) scoped_lock<_Mutex> { |
441 | public: |
442 | typedef _Mutex mutex_type; |
443 | |
444 | private: |
445 | mutex_type& __m_; |
446 | |
447 | public: |
448 | [[nodiscard]] |
449 | _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) |
450 | : __m_(__m) { |
451 | __m_.lock(); |
452 | } |
453 | |
454 | ~scoped_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) { __m_.unlock(); } |
455 | |
456 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t, mutex_type& __m) |
457 | _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m)) |
458 | : __m_(__m) {} |
459 | |
460 | scoped_lock(scoped_lock const&) = delete; |
461 | scoped_lock& operator=(scoped_lock const&) = delete; |
462 | }; |
463 | |
464 | template <class... _MArgs> |
465 | class _LIBCPP_TEMPLATE_VIS scoped_lock { |
466 | static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required" ); |
467 | typedef tuple<_MArgs&...> _MutexTuple; |
468 | |
469 | public: |
470 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) : __t_(__margs...) { |
471 | std::lock(__margs...); |
472 | } |
473 | |
474 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs) : __t_(__margs...) {} |
475 | |
476 | _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { |
477 | typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices; |
478 | __unlock_unpack(_Indices{}, __t_); |
479 | } |
480 | |
481 | scoped_lock(scoped_lock const&) = delete; |
482 | scoped_lock& operator=(scoped_lock const&) = delete; |
483 | |
484 | private: |
485 | template <size_t... _Indx> |
486 | _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) { |
487 | (std::get<_Indx>(__mt).unlock(), ...); |
488 | } |
489 | |
490 | _MutexTuple __t_; |
491 | }; |
492 | _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock); |
493 | |
494 | # endif // _LIBCPP_STD_VER >= 17 |
495 | #endif // !_LIBCPP_HAS_NO_THREADS |
496 | |
497 | _LIBCPP_END_NAMESPACE_STD |
498 | |
499 | _LIBCPP_POP_MACROS |
500 | |
501 | #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 |
502 | # include <atomic> |
503 | # include <concepts> |
504 | # include <cstdlib> |
505 | # include <cstring> |
506 | # include <ctime> |
507 | # include <initializer_list> |
508 | # include <iosfwd> |
509 | # include <new> |
510 | # include <stdexcept> |
511 | # include <system_error> |
512 | # include <type_traits> |
513 | # include <typeinfo> |
514 | #endif |
515 | |
516 | #endif // _LIBCPP_MUTEX |
517 | |