525 lines · plain
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-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP_MUTEX11#define _LIBCPP_MUTEX12 13/*14 mutex synopsis15 16namespace std17{18 19class mutex20{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_mutex37{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_mutex54{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_mutex72{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_guard99{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++17113{114public:115 using mutex_type = Mutex; // Only if sizeof...(MutexTypes) == 1116 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 only124};125 126template <class Mutex>127class unique_lock128{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_flag175{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} // std186 187*/188 189#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)190# include <__cxx03/mutex>191#else192# 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_LANG206# include <tuple>207# endif208# include <version>209 210# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)211# pragma GCC system_header212# endif213 214_LIBCPP_PUSH_MACROS215# include <__undef_macros>216 217_LIBCPP_BEGIN_NAMESPACE_STD218 219# if _LIBCPP_HAS_THREADS220 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 [[__nodiscard__]] bool try_lock() _NOEXCEPT;233 void unlock() _NOEXCEPT;234 235 typedef __libcpp_recursive_mutex_t* native_handle_type;236 237 [[__nodiscard__]] _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 [[__nodiscard__]] bool try_lock() _NOEXCEPT;255 template <class _Rep, class _Period>256 [[__nodiscard__]] _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 [[__nodiscard__]] _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 [[__nodiscard__]] bool try_lock() _NOEXCEPT;292 template <class _Rep, class _Period>293 [[__nodiscard__]] _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 [[__nodiscard__]] _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[[__nodiscard__]] _LIBCPP_NO_THREAD_SAFETY_ANALYSIS _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 } else330 return 1;331 }332 return 0;333}334 335# ifndef _LIBCPP_CXX03_LANG336 337template <class _L0, class _L1, class _L2, class... _L3>338[[__nodiscard__]] _LIBCPP_NO_THREAD_SAFETY_ANALYSIS339 _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {340 int __r = 0;341 unique_lock<_L0> __u0(__l0, try_to_lock);342 if (__u0.owns_lock()) {343 __r = std::try_lock(__l1, __l2, __l3...);344 if (__r == -1)345 __u0.release();346 else347 ++__r;348 }349 return __r;350}351 352# endif // _LIBCPP_CXX03_LANG353 354// We're using unique_lock to implement the functions, which thread annotations don't support. So we have to disable355// the analysis inside the function.356template <class _L0, class _L1>357_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1)358 _LIBCPP_ACQUIRE_CAPABILITY(__l0, __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_LANG380 381template <class _L0, class _L1, class _L2, class... _L3>382_LIBCPP_NO_THREAD_SAFETY_ANALYSIS 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 else407 __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// We're using unique_lock to implement the functions, which thread annotations don't support. So we have to disable418// the analysis inside the function.419template <class _L0, class _L1, class _L2, class... _L3>420_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)421# if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101422 _LIBCPP_ACQUIRE_CAPABILITY(__l0, __l1, __l2, __l3...)423# endif424{425 std::__lock_first(0, __l0, __l1, __l2, __l3...);426}427 428# endif // _LIBCPP_CXX03_LANG429 430# if _LIBCPP_STD_VER >= 17431template <class... _Mutexes>432class scoped_lock;433 434template <>435class scoped_lock<> {436public:437 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock() {}438 ~scoped_lock() = default;439 440 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t) {}441 442 scoped_lock(scoped_lock const&) = delete;443 scoped_lock& operator=(scoped_lock const&) = delete;444};445 446template <class _Mutex>447class _LIBCPP_SCOPED_LOCKABLE scoped_lock<_Mutex> {448public:449 typedef _Mutex mutex_type;450 451private:452 mutex_type& __m_;453 454public:455 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(mutex_type& __m) _LIBCPP_ACQUIRE_CAPABILITY(__m)456 : __m_(__m) {457 __m_.lock();458 }459 460 _LIBCPP_RELEASE_CAPABILITY _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { __m_.unlock(); }461 462 [[nodiscard]]463 _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t, mutex_type& __m) _LIBCPP_REQUIRES_CAPABILITY(__m)464 : __m_(__m) {}465 466 scoped_lock(scoped_lock const&) = delete;467 scoped_lock& operator=(scoped_lock const&) = delete;468};469 470template <class... _MArgs>471class scoped_lock {472 static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required");473 typedef tuple<_MArgs&...> _MutexTuple;474 475public:476 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) : __t_(__margs...) {477 std::lock(__margs...);478 }479 480 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs) : __t_(__margs...) {}481 482 _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { __unlock_unpack(make_index_sequence<sizeof...(_MArgs)>(), __t_); }483 484 scoped_lock(scoped_lock const&) = delete;485 scoped_lock& operator=(scoped_lock const&) = delete;486 487private:488 template <size_t... _Indx>489 _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(index_sequence<_Indx...>, _MutexTuple& __mt) {490 (std::get<_Indx>(__mt).unlock(), ...);491 }492 493 _MutexTuple __t_;494};495_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock);496 497# endif // _LIBCPP_STD_VER >= 17498# endif // _LIBCPP_HAS_THREADS499 500_LIBCPP_END_NAMESPACE_STD501 502_LIBCPP_POP_MACROS503 504# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23505# include <typeinfo>506# endif507 508# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20509# include <atomic>510# include <concepts>511# include <cstdlib>512# include <cstring>513# include <ctime>514# include <initializer_list>515# include <iosfwd>516# include <new>517# include <optional>518# include <stdexcept>519# include <system_error>520# include <type_traits>521# endif522#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)523 524#endif // _LIBCPP_MUTEX525