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 <__threading_support> 15#include <chrono> 16#include <system_error> 17#include <time.h> 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 31class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex 32{ 33 __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER; 34 35public: 36 _LIBCPP_INLINE_VISIBILITY 37 _LIBCPP_CONSTEXPR mutex() = default; 38 39 mutex(const mutex&) = delete; 40 mutex& operator=(const mutex&) = delete; 41 42#if defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION) 43 ~mutex() = default; 44#else 45 ~mutex() _NOEXCEPT; 46#endif 47 48 void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); 49 bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true)); 50 void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()); 51 52 typedef __libcpp_mutex_t* native_handle_type; 53 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;} 54}; 55 56static_assert(is_nothrow_default_constructible<mutex>::value, 57 "the default constructor for std::mutex must be nothrow"); 58 59struct _LIBCPP_TYPE_VIS defer_lock_t { explicit defer_lock_t() = default; }; 60struct _LIBCPP_TYPE_VIS try_to_lock_t { explicit try_to_lock_t() = default; }; 61struct _LIBCPP_TYPE_VIS adopt_lock_t { explicit adopt_lock_t() = default; }; 62 63#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY) 64 65extern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t defer_lock; 66extern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock; 67extern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t adopt_lock; 68 69#else 70 71/* _LIBCPP_INLINE_VAR */ constexpr defer_lock_t defer_lock = defer_lock_t(); 72/* _LIBCPP_INLINE_VAR */ constexpr try_to_lock_t try_to_lock = try_to_lock_t(); 73/* _LIBCPP_INLINE_VAR */ constexpr adopt_lock_t adopt_lock = adopt_lock_t(); 74 75#endif 76 77template <class _Mutex> 78class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) 79lock_guard 80{ 81public: 82 typedef _Mutex mutex_type; 83 84private: 85 mutex_type& __m_; 86public: 87 88 _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY 89 explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) 90 : __m_(__m) {__m_.lock();} 91 92 _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY 93 lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m)) 94 : __m_(__m) {} 95 _LIBCPP_INLINE_VISIBILITY 96 ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();} 97 98private: 99 lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE; 100 lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE; 101}; 102 103template <class _Mutex> 104class _LIBCPP_TEMPLATE_VIS unique_lock 105{ 106public: 107 typedef _Mutex mutex_type; 108 109private: 110 mutex_type* __m_; 111 bool __owns_; 112 113public: 114 _LIBCPP_INLINE_VISIBILITY 115 unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {} 116 _LIBCPP_INLINE_VISIBILITY 117 explicit unique_lock(mutex_type& __m) 118 : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();} 119 _LIBCPP_INLINE_VISIBILITY 120 unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT 121 : __m_(_VSTD::addressof(__m)), __owns_(false) {} 122 _LIBCPP_INLINE_VISIBILITY 123 unique_lock(mutex_type& __m, try_to_lock_t) 124 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {} 125 _LIBCPP_INLINE_VISIBILITY 126 unique_lock(mutex_type& __m, adopt_lock_t) 127 : __m_(_VSTD::addressof(__m)), __owns_(true) {} 128 template <class _Clock, class _Duration> 129 _LIBCPP_INLINE_VISIBILITY 130 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t) 131 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {} 132 template <class _Rep, class _Period> 133 _LIBCPP_INLINE_VISIBILITY 134 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d) 135 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {} 136 _LIBCPP_INLINE_VISIBILITY 137 ~unique_lock() 138 { 139 if (__owns_) 140 __m_->unlock(); 141 } 142 143private: 144 unique_lock(unique_lock const&); // = delete; 145 unique_lock& operator=(unique_lock const&); // = delete; 146 147public: 148 _LIBCPP_INLINE_VISIBILITY 149 unique_lock(unique_lock&& __u) _NOEXCEPT 150 : __m_(__u.__m_), __owns_(__u.__owns_) 151 {__u.__m_ = nullptr; __u.__owns_ = false;} 152 _LIBCPP_INLINE_VISIBILITY 153 unique_lock& operator=(unique_lock&& __u) _NOEXCEPT 154 { 155 if (__owns_) 156 __m_->unlock(); 157 __m_ = __u.__m_; 158 __owns_ = __u.__owns_; 159 __u.__m_ = nullptr; 160 __u.__owns_ = false; 161 return *this; 162 } 163 164 void lock(); 165 bool try_lock(); 166 167 template <class _Rep, class _Period> 168 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d); 169 template <class _Clock, class _Duration> 170 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); 171 172 void unlock(); 173 174 _LIBCPP_INLINE_VISIBILITY 175 void swap(unique_lock& __u) _NOEXCEPT 176 { 177 _VSTD::swap(__m_, __u.__m_); 178 _VSTD::swap(__owns_, __u.__owns_); 179 } 180 _LIBCPP_INLINE_VISIBILITY 181 mutex_type* release() _NOEXCEPT 182 { 183 mutex_type* __m = __m_; 184 __m_ = nullptr; 185 __owns_ = false; 186 return __m; 187 } 188 189 _LIBCPP_INLINE_VISIBILITY 190 bool owns_lock() const _NOEXCEPT {return __owns_;} 191 _LIBCPP_INLINE_VISIBILITY 192 _LIBCPP_EXPLICIT 193 operator bool () const _NOEXCEPT {return __owns_;} 194 _LIBCPP_INLINE_VISIBILITY 195 mutex_type* mutex() const _NOEXCEPT {return __m_;} 196}; 197 198template <class _Mutex> 199void 200unique_lock<_Mutex>::lock() 201{ 202 if (__m_ == nullptr) 203 __throw_system_error(EPERM, "unique_lock::lock: references null mutex"); 204 if (__owns_) 205 __throw_system_error(EDEADLK, "unique_lock::lock: already locked"); 206 __m_->lock(); 207 __owns_ = true; 208} 209 210template <class _Mutex> 211bool 212unique_lock<_Mutex>::try_lock() 213{ 214 if (__m_ == nullptr) 215 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex"); 216 if (__owns_) 217 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked"); 218 __owns_ = __m_->try_lock(); 219 return __owns_; 220} 221 222template <class _Mutex> 223template <class _Rep, class _Period> 224bool 225unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) 226{ 227 if (__m_ == nullptr) 228 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex"); 229 if (__owns_) 230 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked"); 231 __owns_ = __m_->try_lock_for(__d); 232 return __owns_; 233} 234 235template <class _Mutex> 236template <class _Clock, class _Duration> 237bool 238unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 239{ 240 if (__m_ == nullptr) 241 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex"); 242 if (__owns_) 243 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked"); 244 __owns_ = __m_->try_lock_until(__t); 245 return __owns_; 246} 247 248template <class _Mutex> 249void 250unique_lock<_Mutex>::unlock() 251{ 252 if (!__owns_) 253 __throw_system_error(EPERM, "unique_lock::unlock: not locked"); 254 __m_->unlock(); 255 __owns_ = false; 256} 257 258template <class _Mutex> 259inline _LIBCPP_INLINE_VISIBILITY 260void 261swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT 262 {__x.swap(__y);} 263 264//enum class cv_status 265_LIBCPP_DECLARE_STRONG_ENUM(cv_status) 266{ 267 no_timeout, 268 timeout 269}; 270_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status) 271 272class _LIBCPP_TYPE_VIS condition_variable 273{ 274 __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER; 275public: 276 _LIBCPP_INLINE_VISIBILITY 277 _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default; 278 279#ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION 280 ~condition_variable() = default; 281#else 282 ~condition_variable(); 283#endif 284 285 condition_variable(const condition_variable&) = delete; 286 condition_variable& operator=(const condition_variable&) = delete; 287 288 void notify_one() _NOEXCEPT; 289 void notify_all() _NOEXCEPT; 290 291 void wait(unique_lock<mutex>& __lk) _NOEXCEPT; 292 template <class _Predicate> 293 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 294 void wait(unique_lock<mutex>& __lk, _Predicate __pred); 295 296 template <class _Clock, class _Duration> 297 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 298 cv_status 299 wait_until(unique_lock<mutex>& __lk, 300 const chrono::time_point<_Clock, _Duration>& __t); 301 302 template <class _Clock, class _Duration, class _Predicate> 303 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 304 bool 305 wait_until(unique_lock<mutex>& __lk, 306 const chrono::time_point<_Clock, _Duration>& __t, 307 _Predicate __pred); 308 309 template <class _Rep, class _Period> 310 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 311 cv_status 312 wait_for(unique_lock<mutex>& __lk, 313 const chrono::duration<_Rep, _Period>& __d); 314 315 template <class _Rep, class _Period, class _Predicate> 316 bool 317 _LIBCPP_INLINE_VISIBILITY 318 wait_for(unique_lock<mutex>& __lk, 319 const chrono::duration<_Rep, _Period>& __d, 320 _Predicate __pred); 321 322 typedef __libcpp_condvar_t* native_handle_type; 323 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;} 324 325private: 326 void __do_timed_wait(unique_lock<mutex>& __lk, 327 chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT; 328#if defined(_LIBCPP_HAS_COND_CLOCKWAIT) 329 void __do_timed_wait(unique_lock<mutex>& __lk, 330 chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT; 331#endif 332 template <class _Clock> 333 void __do_timed_wait(unique_lock<mutex>& __lk, 334 chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT; 335}; 336#endif // !_LIBCPP_HAS_NO_THREADS 337 338template <class _Rep, class _Period> 339inline _LIBCPP_INLINE_VISIBILITY 340typename enable_if 341< 342 is_floating_point<_Rep>::value, 343 chrono::nanoseconds 344>::type 345__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) 346{ 347 using namespace chrono; 348 using __ratio = ratio_divide<_Period, nano>; 349 using __ns_rep = nanoseconds::rep; 350 _Rep __result_float = __d.count() * __ratio::num / __ratio::den; 351 352 _Rep __result_max = numeric_limits<__ns_rep>::max(); 353 if (__result_float >= __result_max) { 354 return nanoseconds::max(); 355 } 356 357 _Rep __result_min = numeric_limits<__ns_rep>::min(); 358 if (__result_float <= __result_min) { 359 return nanoseconds::min(); 360 } 361 362 return nanoseconds(static_cast<__ns_rep>(__result_float)); 363} 364 365template <class _Rep, class _Period> 366inline _LIBCPP_INLINE_VISIBILITY 367typename enable_if 368< 369 !is_floating_point<_Rep>::value, 370 chrono::nanoseconds 371>::type 372__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) 373{ 374 using namespace chrono; 375 if (__d.count() == 0) { 376 return nanoseconds(0); 377 } 378 379 using __ratio = ratio_divide<_Period, nano>; 380 using __ns_rep = nanoseconds::rep; 381 __ns_rep __result_max = numeric_limits<__ns_rep>::max(); 382 if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) { 383 return nanoseconds::max(); 384 } 385 386 __ns_rep __result_min = numeric_limits<__ns_rep>::min(); 387 if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) { 388 return nanoseconds::min(); 389 } 390 391 __ns_rep __result = __d.count() * __ratio::num / __ratio::den; 392 if (__result == 0) { 393 return nanoseconds(1); 394 } 395 396 return nanoseconds(__result); 397} 398 399#ifndef _LIBCPP_HAS_NO_THREADS 400template <class _Predicate> 401void 402condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) 403{ 404 while (!__pred()) 405 wait(__lk); 406} 407 408template <class _Clock, class _Duration> 409cv_status 410condition_variable::wait_until(unique_lock<mutex>& __lk, 411 const chrono::time_point<_Clock, _Duration>& __t) 412{ 413 using namespace chrono; 414 using __clock_tp_ns = time_point<_Clock, nanoseconds>; 415 416 typename _Clock::time_point __now = _Clock::now(); 417 if (__t <= __now) 418 return cv_status::timeout; 419 420 __clock_tp_ns __t_ns = __clock_tp_ns(_VSTD::__safe_nanosecond_cast(__t.time_since_epoch())); 421 422 __do_timed_wait(__lk, __t_ns); 423 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout; 424} 425 426template <class _Clock, class _Duration, class _Predicate> 427bool 428condition_variable::wait_until(unique_lock<mutex>& __lk, 429 const chrono::time_point<_Clock, _Duration>& __t, 430 _Predicate __pred) 431{ 432 while (!__pred()) 433 { 434 if (wait_until(__lk, __t) == cv_status::timeout) 435 return __pred(); 436 } 437 return true; 438} 439 440template <class _Rep, class _Period> 441cv_status 442condition_variable::wait_for(unique_lock<mutex>& __lk, 443 const chrono::duration<_Rep, _Period>& __d) 444{ 445 using namespace chrono; 446 if (__d <= __d.zero()) 447 return cv_status::timeout; 448 using __ns_rep = nanoseconds::rep; 449 steady_clock::time_point __c_now = steady_clock::now(); 450 451#if defined(_LIBCPP_HAS_COND_CLOCKWAIT) 452 using __clock_tp_ns = time_point<steady_clock, nanoseconds>; 453 __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(__c_now.time_since_epoch()).count(); 454#else 455 using __clock_tp_ns = time_point<system_clock, nanoseconds>; 456 __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count(); 457#endif 458 459 __ns_rep __d_ns_count = _VSTD::__safe_nanosecond_cast(__d).count(); 460 461 if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) { 462 __do_timed_wait(__lk, __clock_tp_ns::max()); 463 } else { 464 __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count))); 465 } 466 467 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : 468 cv_status::timeout; 469} 470 471template <class _Rep, class _Period, class _Predicate> 472inline 473bool 474condition_variable::wait_for(unique_lock<mutex>& __lk, 475 const chrono::duration<_Rep, _Period>& __d, 476 _Predicate __pred) 477{ 478 return wait_until(__lk, chrono::steady_clock::now() + __d, 479 _VSTD::move(__pred)); 480} 481 482#if defined(_LIBCPP_HAS_COND_CLOCKWAIT) 483inline 484void 485condition_variable::__do_timed_wait(unique_lock<mutex>& __lk, 486 chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT 487{ 488 using namespace chrono; 489 if (!__lk.owns_lock()) 490 __throw_system_error(EPERM, 491 "condition_variable::timed wait: mutex not locked"); 492 nanoseconds __d = __tp.time_since_epoch(); 493 timespec __ts; 494 seconds __s = duration_cast<seconds>(__d); 495 using __ts_sec = decltype(__ts.tv_sec); 496 const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max(); 497 if (__s.count() < __ts_sec_max) 498 { 499 __ts.tv_sec = static_cast<__ts_sec>(__s.count()); 500 __ts.tv_nsec = (__d - __s).count(); 501 } 502 else 503 { 504 __ts.tv_sec = __ts_sec_max; 505 __ts.tv_nsec = giga::num - 1; 506 } 507 int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts); 508 if (__ec != 0 && __ec != ETIMEDOUT) 509 __throw_system_error(__ec, "condition_variable timed_wait failed"); 510} 511#endif // _LIBCPP_HAS_COND_CLOCKWAIT 512 513template <class _Clock> 514inline 515void 516condition_variable::__do_timed_wait(unique_lock<mutex>& __lk, 517 chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT 518{ 519 wait_for(__lk, __tp - _Clock::now()); 520} 521 522#endif // !_LIBCPP_HAS_NO_THREADS 523 524_LIBCPP_END_NAMESPACE_STD 525 526_LIBCPP_POP_MACROS 527 528#endif // _LIBCPP___MUTEX_BASE 529