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#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 221class _LIBCPP_EXPORTED_FROM_ABI recursive_mutex { 222 __libcpp_recursive_mutex_t __m_; 223 224public: 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 240class _LIBCPP_EXPORTED_FROM_ABI timed_mutex { 241 mutex __m_; 242 condition_variable __cv_; 243 bool __locked_; 244 245public: 246 timed_mutex(); 247 ~timed_mutex(); 248 249 timed_mutex(const timed_mutex&) = delete; 250 timed_mutex& operator=(const timed_mutex&) = delete; 251 252public: 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 277class _LIBCPP_EXPORTED_FROM_ABI recursive_timed_mutex { 278 mutex __m_; 279 condition_variable __cv_; 280 size_t __count_; 281 __thread_id __id_; 282 283public: 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 322template <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 337template <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 353template <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 377template <class _L0, class _L1, class _L2, class... _L3> 378void __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 413template <class _L0, class _L1, class _L2, class... _L3> 414inline _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 421template <class... _Mutexes> 422class scoped_lock; 423 424template <> 425class scoped_lock<> { 426public: 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 436template <class _Mutex> 437class _LIBCPP_SCOPED_LOCKABLE scoped_lock<_Mutex> { 438public: 439 typedef _Mutex mutex_type; 440 441private: 442 mutex_type& __m_; 443 444public: 445 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(mutex_type& __m) _LIBCPP_ACQUIRE_CAPABILITY(__m) 446 : __m_(__m) { 447 __m_.lock(); 448 } 449 450 _LIBCPP_RELEASE_CAPABILITY _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { __m_.unlock(); } 451 452 [[nodiscard]] 453 _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t, mutex_type& __m) _LIBCPP_REQUIRES_CAPABILITY(__m) 454 : __m_(__m) {} 455 456 scoped_lock(scoped_lock const&) = delete; 457 scoped_lock& operator=(scoped_lock const&) = delete; 458}; 459 460template <class... _MArgs> 461class scoped_lock { 462 static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required"); 463 typedef tuple<_MArgs&...> _MutexTuple; 464 465public: 466 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) : __t_(__margs...) { 467 std::lock(__margs...); 468 } 469 470 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs) : __t_(__margs...) {} 471 472 _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { 473 typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices; 474 __unlock_unpack(_Indices{}, __t_); 475 } 476 477 scoped_lock(scoped_lock const&) = delete; 478 scoped_lock& operator=(scoped_lock const&) = delete; 479 480private: 481 template <size_t... _Indx> 482 _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) { 483 (std::get<_Indx>(__mt).unlock(), ...); 484 } 485 486 _MutexTuple __t_; 487}; 488_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock); 489 490# endif // _LIBCPP_STD_VER >= 17 491# endif // _LIBCPP_HAS_THREADS 492 493_LIBCPP_END_NAMESPACE_STD 494 495_LIBCPP_POP_MACROS 496 497# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 498# include <atomic> 499# include <concepts> 500# include <cstdlib> 501# include <cstring> 502# include <ctime> 503# include <initializer_list> 504# include <iosfwd> 505# include <new> 506# include <optional> 507# include <stdexcept> 508# include <system_error> 509# include <type_traits> 510# include <typeinfo> 511# endif 512#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) 513 514#endif // _LIBCPP_MUTEX 515