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