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