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 16namespace std 17{ 18 19class mutex 20{ 21public: 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 36class recursive_mutex 37{ 38public: 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 53class timed_mutex 54{ 55public: 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 71class recursive_timed_mutex 72{ 73public: 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 89struct defer_lock_t { explicit defer_lock_t() = default; }; 90struct try_to_lock_t { explicit try_to_lock_t() = default; }; 91struct adopt_lock_t { explicit adopt_lock_t() = default; }; 92 93inline constexpr defer_lock_t defer_lock{}; 94inline constexpr try_to_lock_t try_to_lock{}; 95inline constexpr adopt_lock_t adopt_lock{}; 96 97template <class Mutex> 98class lock_guard 99{ 100public: 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 111template <class... MutexTypes> 112class scoped_lock // C++17 113{ 114public: 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; 122private: 123 tuple<MutexTypes&...> pm; // exposition only 124}; 125 126template <class Mutex> 127class unique_lock 128{ 129public: 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 166template <class Mutex> 167 void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept; 168 169template <class L1, class L2, class... L3> 170 int try_lock(L1&, L2&, L3&...); 171template <class L1, class L2, class... L3> 172 void lock(L1&, L2&, L3&...); 173 174struct 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 182template<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 218_LIBCPP_BEGIN_NAMESPACE_STD 219 220#ifndef _LIBCPP_HAS_NO_THREADS 221 222class _LIBCPP_EXPORTED_FROM_ABI recursive_mutex 223{ 224 __libcpp_recursive_mutex_t __m_; 225 226public: 227 recursive_mutex(); 228 ~recursive_mutex(); 229 230 recursive_mutex(const recursive_mutex&) = delete; 231 recursive_mutex& operator=(const recursive_mutex&) = delete; 232 233 void lock(); 234 bool try_lock() _NOEXCEPT; 235 void unlock() _NOEXCEPT; 236 237 typedef __libcpp_recursive_mutex_t* native_handle_type; 238 239 _LIBCPP_INLINE_VISIBILITY 240 native_handle_type native_handle() {return &__m_;} 241}; 242 243class _LIBCPP_EXPORTED_FROM_ABI timed_mutex 244{ 245 mutex __m_; 246 condition_variable __cv_; 247 bool __locked_; 248public: 249 timed_mutex(); 250 ~timed_mutex(); 251 252 timed_mutex(const timed_mutex&) = delete; 253 timed_mutex& operator=(const timed_mutex&) = delete; 254 255public: 256 void lock(); 257 bool try_lock() _NOEXCEPT; 258 template <class _Rep, class _Period> 259 _LIBCPP_INLINE_VISIBILITY 260 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) 261 {return try_lock_until(chrono::steady_clock::now() + __d);} 262 template <class _Clock, class _Duration> 263 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 264 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); 265 void unlock() _NOEXCEPT; 266}; 267 268template <class _Clock, class _Duration> 269bool 270timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 271{ 272 using namespace chrono; 273 unique_lock<mutex> __lk(__m_); 274 bool __no_timeout = _Clock::now() < __t; 275 while (__no_timeout && __locked_) 276 __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout; 277 if (!__locked_) 278 { 279 __locked_ = true; 280 return true; 281 } 282 return false; 283} 284 285class _LIBCPP_EXPORTED_FROM_ABI recursive_timed_mutex 286{ 287 mutex __m_; 288 condition_variable __cv_; 289 size_t __count_; 290 __thread_id __id_; 291public: 292 recursive_timed_mutex(); 293 ~recursive_timed_mutex(); 294 295 recursive_timed_mutex(const recursive_timed_mutex&) = delete; 296 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 297 298 void lock(); 299 bool try_lock() _NOEXCEPT; 300 template <class _Rep, class _Period> 301 _LIBCPP_INLINE_VISIBILITY 302 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) 303 {return try_lock_until(chrono::steady_clock::now() + __d);} 304 template <class _Clock, class _Duration> 305 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 306 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); 307 void unlock() _NOEXCEPT; 308}; 309 310template <class _Clock, class _Duration> 311bool 312recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 313{ 314 using namespace chrono; 315 __thread_id __id = this_thread::get_id(); 316 unique_lock<mutex> __lk(__m_); 317 if (__id == __id_) 318 { 319 if (__count_ == numeric_limits<size_t>::max()) 320 return false; 321 ++__count_; 322 return true; 323 } 324 bool __no_timeout = _Clock::now() < __t; 325 while (__no_timeout && __count_ != 0) 326 __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout; 327 if (__count_ == 0) 328 { 329 __count_ = 1; 330 __id_ = __id; 331 return true; 332 } 333 return false; 334} 335 336template <class _L0, class _L1> 337_LIBCPP_HIDE_FROM_ABI int 338try_lock(_L0& __l0, _L1& __l1) 339{ 340 unique_lock<_L0> __u0(__l0, try_to_lock_t()); 341 if (__u0.owns_lock()) 342 { 343 if (__l1.try_lock()) 344 { 345 __u0.release(); 346 return -1; 347 } 348 else 349 return 1; 350 } 351 return 0; 352} 353 354#ifndef _LIBCPP_CXX03_LANG 355 356template <class _L0, class _L1, class _L2, class... _L3> 357_LIBCPP_HIDE_FROM_ABI int 358try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) 359{ 360 int __r = 0; 361 unique_lock<_L0> __u0(__l0, try_to_lock); 362 if (__u0.owns_lock()) 363 { 364 __r = std::try_lock(__l1, __l2, __l3...); 365 if (__r == -1) 366 __u0.release(); 367 else 368 ++__r; 369 } 370 return __r; 371} 372 373#endif // _LIBCPP_CXX03_LANG 374 375template <class _L0, class _L1> 376_LIBCPP_HIDE_FROM_ABI void 377lock(_L0& __l0, _L1& __l1) 378{ 379 while (true) 380 { 381 { 382 unique_lock<_L0> __u0(__l0); 383 if (__l1.try_lock()) 384 { 385 __u0.release(); 386 break; 387 } 388 } 389 __libcpp_thread_yield(); 390 { 391 unique_lock<_L1> __u1(__l1); 392 if (__l0.try_lock()) 393 { 394 __u1.release(); 395 break; 396 } 397 } 398 __libcpp_thread_yield(); 399 } 400} 401 402#ifndef _LIBCPP_CXX03_LANG 403 404template <class _L0, class _L1, class _L2, class ..._L3> 405void 406__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3) 407{ 408 while (true) 409 { 410 switch (__i) 411 { 412 case 0: 413 { 414 unique_lock<_L0> __u0(__l0); 415 __i = std::try_lock(__l1, __l2, __l3...); 416 if (__i == -1) 417 { 418 __u0.release(); 419 return; 420 } 421 } 422 ++__i; 423 __libcpp_thread_yield(); 424 break; 425 case 1: 426 { 427 unique_lock<_L1> __u1(__l1); 428 __i = std::try_lock(__l2, __l3..., __l0); 429 if (__i == -1) 430 { 431 __u1.release(); 432 return; 433 } 434 } 435 if (__i == sizeof...(_L3) + 1) 436 __i = 0; 437 else 438 __i += 2; 439 __libcpp_thread_yield(); 440 break; 441 default: 442 std::__lock_first(__i - 2, __l2, __l3..., __l0, __l1); 443 return; 444 } 445 } 446} 447 448template <class _L0, class _L1, class _L2, class ..._L3> 449inline _LIBCPP_INLINE_VISIBILITY 450void 451lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3) 452{ 453 std::__lock_first(0, __l0, __l1, __l2, __l3...); 454} 455 456template <class _L0> 457inline _LIBCPP_INLINE_VISIBILITY 458void __unlock(_L0& __l0) { 459 __l0.unlock(); 460} 461 462template <class _L0, class _L1> 463inline _LIBCPP_INLINE_VISIBILITY 464void __unlock(_L0& __l0, _L1& __l1) { 465 __l0.unlock(); 466 __l1.unlock(); 467} 468 469template <class _L0, class _L1, class _L2, class ..._L3> 470inline _LIBCPP_INLINE_VISIBILITY 471void __unlock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { 472 __l0.unlock(); 473 __l1.unlock(); 474 _VSTD::__unlock(__l2, __l3...); 475} 476 477#endif // _LIBCPP_CXX03_LANG 478 479#if _LIBCPP_STD_VER >= 17 480template <class ..._Mutexes> 481class _LIBCPP_TEMPLATE_VIS scoped_lock; 482 483template <> 484class _LIBCPP_TEMPLATE_VIS scoped_lock<> { 485public: 486 explicit scoped_lock() {} 487 ~scoped_lock() = default; 488 489 _LIBCPP_INLINE_VISIBILITY 490 explicit scoped_lock(adopt_lock_t) {} 491 492 scoped_lock(scoped_lock const&) = delete; 493 scoped_lock& operator=(scoped_lock const&) = delete; 494}; 495 496template <class _Mutex> 497class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) scoped_lock<_Mutex> { 498public: 499 typedef _Mutex mutex_type; 500private: 501 mutex_type& __m_; 502public: 503 explicit scoped_lock(mutex_type & __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) 504 : __m_(__m) {__m_.lock();} 505 506 ~scoped_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();} 507 508 _LIBCPP_INLINE_VISIBILITY 509 explicit scoped_lock(adopt_lock_t, mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m)) 510 : __m_(__m) {} 511 512 scoped_lock(scoped_lock const&) = delete; 513 scoped_lock& operator=(scoped_lock const&) = delete; 514}; 515 516template <class ..._MArgs> 517class _LIBCPP_TEMPLATE_VIS scoped_lock 518{ 519 static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required"); 520 typedef tuple<_MArgs&...> _MutexTuple; 521 522public: 523 _LIBCPP_INLINE_VISIBILITY 524 explicit scoped_lock(_MArgs&... __margs) 525 : __t_(__margs...) 526 { 527 _VSTD::lock(__margs...); 528 } 529 530 _LIBCPP_INLINE_VISIBILITY 531 scoped_lock(adopt_lock_t, _MArgs&... __margs) 532 : __t_(__margs...) 533 { 534 } 535 536 _LIBCPP_INLINE_VISIBILITY 537 ~scoped_lock() { 538 typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices; 539 __unlock_unpack(_Indices{}, __t_); 540 } 541 542 scoped_lock(scoped_lock const&) = delete; 543 scoped_lock& operator=(scoped_lock const&) = delete; 544 545private: 546 template <size_t ..._Indx> 547 _LIBCPP_INLINE_VISIBILITY 548 static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) { 549 _VSTD::__unlock(_VSTD::get<_Indx>(__mt)...); 550 } 551 552 _MutexTuple __t_; 553}; 554_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock); 555 556#endif // _LIBCPP_STD_VER >= 17 557#endif // !_LIBCPP_HAS_NO_THREADS 558 559_LIBCPP_END_NAMESPACE_STD 560 561_LIBCPP_POP_MACROS 562 563#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 564# include <atomic> 565# include <concepts> 566# include <cstdlib> 567# include <cstring> 568# include <ctime> 569# include <initializer_list> 570# include <iosfwd> 571# include <new> 572# include <stdexcept> 573# include <system_error> 574# include <type_traits> 575# include <typeinfo> 576#endif 577 578#endif // _LIBCPP_MUTEX 579