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