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_BASE 11#define _LIBCPP___MUTEX_BASE 12 13#include <__config> 14#include <chrono> 15#include <system_error> 16#include <__threading_support> 17 18 19#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 20#pragma GCC system_header 21#endif 22 23_LIBCPP_PUSH_MACROS 24#include <__undef_macros> 25 26 27_LIBCPP_BEGIN_NAMESPACE_STD 28 29#ifndef _LIBCPP_HAS_NO_THREADS 30 31#ifndef _LIBCPP_THREAD_SAFETY_ANNOTATION 32# ifdef _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS 33# define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x)) 34# else 35# define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) 36# endif 37#endif // _LIBCPP_THREAD_SAFETY_ANNOTATION 38 39class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex 40{ 41#ifndef _LIBCPP_CXX03_LANG 42 __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER; 43#else 44 __libcpp_mutex_t __m_; 45#endif 46 47public: 48 _LIBCPP_INLINE_VISIBILITY 49#ifndef _LIBCPP_CXX03_LANG 50 constexpr mutex() = default; 51#else 52 mutex() _NOEXCEPT {__m_ = (__libcpp_mutex_t)_LIBCPP_MUTEX_INITIALIZER;} 53#endif 54 ~mutex(); 55 56private: 57 mutex(const mutex&);// = delete; 58 mutex& operator=(const mutex&);// = delete; 59 60public: 61 void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); 62 bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true)); 63 void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()); 64 65 typedef __libcpp_mutex_t* native_handle_type; 66 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;} 67}; 68 69static_assert(is_nothrow_default_constructible<mutex>::value, 70 "the default constructor for std::mutex must be nothrow"); 71 72struct _LIBCPP_TYPE_VIS defer_lock_t {}; 73struct _LIBCPP_TYPE_VIS try_to_lock_t {}; 74struct _LIBCPP_TYPE_VIS adopt_lock_t {}; 75 76#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY) 77 78extern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t defer_lock; 79extern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock; 80extern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t adopt_lock; 81 82#else 83 84/* _LIBCPP_INLINE_VAR */ constexpr defer_lock_t defer_lock = defer_lock_t(); 85/* _LIBCPP_INLINE_VAR */ constexpr try_to_lock_t try_to_lock = try_to_lock_t(); 86/* _LIBCPP_INLINE_VAR */ constexpr adopt_lock_t adopt_lock = adopt_lock_t(); 87 88#endif 89 90template <class _Mutex> 91class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) 92lock_guard 93{ 94public: 95 typedef _Mutex mutex_type; 96 97private: 98 mutex_type& __m_; 99public: 100 101 _LIBCPP_INLINE_VISIBILITY 102 explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) 103 : __m_(__m) {__m_.lock();} 104 _LIBCPP_INLINE_VISIBILITY 105 lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m)) 106 : __m_(__m) {} 107 _LIBCPP_INLINE_VISIBILITY 108 ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();} 109 110private: 111 lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE; 112 lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE; 113}; 114 115template <class _Mutex> 116class _LIBCPP_TEMPLATE_VIS unique_lock 117{ 118public: 119 typedef _Mutex mutex_type; 120 121private: 122 mutex_type* __m_; 123 bool __owns_; 124 125public: 126 _LIBCPP_INLINE_VISIBILITY 127 unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {} 128 _LIBCPP_INLINE_VISIBILITY 129 explicit unique_lock(mutex_type& __m) 130 : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();} 131 _LIBCPP_INLINE_VISIBILITY 132 unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT 133 : __m_(_VSTD::addressof(__m)), __owns_(false) {} 134 _LIBCPP_INLINE_VISIBILITY 135 unique_lock(mutex_type& __m, try_to_lock_t) 136 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {} 137 _LIBCPP_INLINE_VISIBILITY 138 unique_lock(mutex_type& __m, adopt_lock_t) 139 : __m_(_VSTD::addressof(__m)), __owns_(true) {} 140 template <class _Clock, class _Duration> 141 _LIBCPP_INLINE_VISIBILITY 142 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t) 143 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {} 144 template <class _Rep, class _Period> 145 _LIBCPP_INLINE_VISIBILITY 146 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d) 147 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {} 148 _LIBCPP_INLINE_VISIBILITY 149 ~unique_lock() 150 { 151 if (__owns_) 152 __m_->unlock(); 153 } 154 155private: 156 unique_lock(unique_lock const&); // = delete; 157 unique_lock& operator=(unique_lock const&); // = delete; 158 159public: 160#ifndef _LIBCPP_CXX03_LANG 161 _LIBCPP_INLINE_VISIBILITY 162 unique_lock(unique_lock&& __u) _NOEXCEPT 163 : __m_(__u.__m_), __owns_(__u.__owns_) 164 {__u.__m_ = nullptr; __u.__owns_ = false;} 165 _LIBCPP_INLINE_VISIBILITY 166 unique_lock& operator=(unique_lock&& __u) _NOEXCEPT 167 { 168 if (__owns_) 169 __m_->unlock(); 170 __m_ = __u.__m_; 171 __owns_ = __u.__owns_; 172 __u.__m_ = nullptr; 173 __u.__owns_ = false; 174 return *this; 175 } 176 177#endif // _LIBCPP_CXX03_LANG 178 179 void lock(); 180 bool try_lock(); 181 182 template <class _Rep, class _Period> 183 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d); 184 template <class _Clock, class _Duration> 185 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); 186 187 void unlock(); 188 189 _LIBCPP_INLINE_VISIBILITY 190 void swap(unique_lock& __u) _NOEXCEPT 191 { 192 _VSTD::swap(__m_, __u.__m_); 193 _VSTD::swap(__owns_, __u.__owns_); 194 } 195 _LIBCPP_INLINE_VISIBILITY 196 mutex_type* release() _NOEXCEPT 197 { 198 mutex_type* __m = __m_; 199 __m_ = nullptr; 200 __owns_ = false; 201 return __m; 202 } 203 204 _LIBCPP_INLINE_VISIBILITY 205 bool owns_lock() const _NOEXCEPT {return __owns_;} 206 _LIBCPP_INLINE_VISIBILITY 207 _LIBCPP_EXPLICIT 208 operator bool () const _NOEXCEPT {return __owns_;} 209 _LIBCPP_INLINE_VISIBILITY 210 mutex_type* mutex() const _NOEXCEPT {return __m_;} 211}; 212 213template <class _Mutex> 214void 215unique_lock<_Mutex>::lock() 216{ 217 if (__m_ == nullptr) 218 __throw_system_error(EPERM, "unique_lock::lock: references null mutex"); 219 if (__owns_) 220 __throw_system_error(EDEADLK, "unique_lock::lock: already locked"); 221 __m_->lock(); 222 __owns_ = true; 223} 224 225template <class _Mutex> 226bool 227unique_lock<_Mutex>::try_lock() 228{ 229 if (__m_ == nullptr) 230 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex"); 231 if (__owns_) 232 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked"); 233 __owns_ = __m_->try_lock(); 234 return __owns_; 235} 236 237template <class _Mutex> 238template <class _Rep, class _Period> 239bool 240unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) 241{ 242 if (__m_ == nullptr) 243 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex"); 244 if (__owns_) 245 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked"); 246 __owns_ = __m_->try_lock_for(__d); 247 return __owns_; 248} 249 250template <class _Mutex> 251template <class _Clock, class _Duration> 252bool 253unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 254{ 255 if (__m_ == nullptr) 256 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex"); 257 if (__owns_) 258 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked"); 259 __owns_ = __m_->try_lock_until(__t); 260 return __owns_; 261} 262 263template <class _Mutex> 264void 265unique_lock<_Mutex>::unlock() 266{ 267 if (!__owns_) 268 __throw_system_error(EPERM, "unique_lock::unlock: not locked"); 269 __m_->unlock(); 270 __owns_ = false; 271} 272 273template <class _Mutex> 274inline _LIBCPP_INLINE_VISIBILITY 275void 276swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT 277 {__x.swap(__y);} 278 279//enum class cv_status 280_LIBCPP_DECLARE_STRONG_ENUM(cv_status) 281{ 282 no_timeout, 283 timeout 284}; 285_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status) 286 287class _LIBCPP_TYPE_VIS condition_variable 288{ 289#ifndef _LIBCPP_CXX03_LANG 290 __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER; 291#else 292 __libcpp_condvar_t __cv_; 293#endif 294 295public: 296 _LIBCPP_INLINE_VISIBILITY 297#ifndef _LIBCPP_CXX03_LANG 298 constexpr condition_variable() _NOEXCEPT = default; 299#else 300 condition_variable() _NOEXCEPT {__cv_ = (__libcpp_condvar_t)_LIBCPP_CONDVAR_INITIALIZER;} 301#endif 302 ~condition_variable(); 303 304private: 305 condition_variable(const condition_variable&); // = delete; 306 condition_variable& operator=(const condition_variable&); // = delete; 307 308public: 309 void notify_one() _NOEXCEPT; 310 void notify_all() _NOEXCEPT; 311 312 void wait(unique_lock<mutex>& __lk) _NOEXCEPT; 313 template <class _Predicate> 314 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 315 void wait(unique_lock<mutex>& __lk, _Predicate __pred); 316 317 template <class _Clock, class _Duration> 318 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 319 cv_status 320 wait_until(unique_lock<mutex>& __lk, 321 const chrono::time_point<_Clock, _Duration>& __t); 322 323 template <class _Clock, class _Duration, class _Predicate> 324 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 325 bool 326 wait_until(unique_lock<mutex>& __lk, 327 const chrono::time_point<_Clock, _Duration>& __t, 328 _Predicate __pred); 329 330 template <class _Rep, class _Period> 331 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 332 cv_status 333 wait_for(unique_lock<mutex>& __lk, 334 const chrono::duration<_Rep, _Period>& __d); 335 336 template <class _Rep, class _Period, class _Predicate> 337 bool 338 _LIBCPP_INLINE_VISIBILITY 339 wait_for(unique_lock<mutex>& __lk, 340 const chrono::duration<_Rep, _Period>& __d, 341 _Predicate __pred); 342 343 typedef __libcpp_condvar_t* native_handle_type; 344 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;} 345 346private: 347 void __do_timed_wait(unique_lock<mutex>& __lk, 348 chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT; 349}; 350#endif // !_LIBCPP_HAS_NO_THREADS 351 352template <class _To, class _Rep, class _Period> 353inline _LIBCPP_INLINE_VISIBILITY 354typename enable_if 355< 356 chrono::__is_duration<_To>::value, 357 _To 358>::type 359__ceil(chrono::duration<_Rep, _Period> __d) 360{ 361 using namespace chrono; 362 _To __r = duration_cast<_To>(__d); 363 if (__r < __d) 364 ++__r; 365 return __r; 366} 367 368#ifndef _LIBCPP_HAS_NO_THREADS 369template <class _Predicate> 370void 371condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) 372{ 373 while (!__pred()) 374 wait(__lk); 375} 376 377template <class _Clock, class _Duration> 378cv_status 379condition_variable::wait_until(unique_lock<mutex>& __lk, 380 const chrono::time_point<_Clock, _Duration>& __t) 381{ 382 using namespace chrono; 383 wait_for(__lk, __t - _Clock::now()); 384 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout; 385} 386 387template <class _Clock, class _Duration, class _Predicate> 388bool 389condition_variable::wait_until(unique_lock<mutex>& __lk, 390 const chrono::time_point<_Clock, _Duration>& __t, 391 _Predicate __pred) 392{ 393 while (!__pred()) 394 { 395 if (wait_until(__lk, __t) == cv_status::timeout) 396 return __pred(); 397 } 398 return true; 399} 400 401template <class _Rep, class _Period> 402cv_status 403condition_variable::wait_for(unique_lock<mutex>& __lk, 404 const chrono::duration<_Rep, _Period>& __d) 405{ 406 using namespace chrono; 407 if (__d <= __d.zero()) 408 return cv_status::timeout; 409 typedef time_point<system_clock, duration<long double, nano> > __sys_tpf; 410 typedef time_point<system_clock, nanoseconds> __sys_tpi; 411 __sys_tpf _Max = __sys_tpi::max(); 412 steady_clock::time_point __c_now = steady_clock::now(); 413 system_clock::time_point __s_now = system_clock::now(); 414 if (_Max - __d > __s_now) 415 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d)); 416 else 417 __do_timed_wait(__lk, __sys_tpi::max()); 418 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : 419 cv_status::timeout; 420} 421 422template <class _Rep, class _Period, class _Predicate> 423inline 424bool 425condition_variable::wait_for(unique_lock<mutex>& __lk, 426 const chrono::duration<_Rep, _Period>& __d, 427 _Predicate __pred) 428{ 429 return wait_until(__lk, chrono::steady_clock::now() + __d, 430 _VSTD::move(__pred)); 431} 432 433#endif // !_LIBCPP_HAS_NO_THREADS 434 435_LIBCPP_END_NAMESPACE_STD 436 437_LIBCPP_POP_MACROS 438 439#endif // _LIBCPP___MUTEX_BASE 440