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