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/* inline */ constexpr defer_lock_t defer_lock = defer_lock_t(); 72/* inline */ constexpr try_to_lock_t try_to_lock = try_to_lock_t(); 73/* inline */ 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&) = delete; 100 lock_guard& operator=(lock_guard const&) = 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 143 unique_lock(unique_lock const&) = delete; 144 unique_lock& operator=(unique_lock const&) = delete; 145 146 _LIBCPP_INLINE_VISIBILITY 147 unique_lock(unique_lock&& __u) _NOEXCEPT 148 : __m_(__u.__m_), __owns_(__u.__owns_) 149 {__u.__m_ = nullptr; __u.__owns_ = false;} 150 _LIBCPP_INLINE_VISIBILITY 151 unique_lock& operator=(unique_lock&& __u) _NOEXCEPT 152 { 153 if (__owns_) 154 __m_->unlock(); 155 __m_ = __u.__m_; 156 __owns_ = __u.__owns_; 157 __u.__m_ = nullptr; 158 __u.__owns_ = false; 159 return *this; 160 } 161 162 void lock(); 163 bool try_lock(); 164 165 template <class _Rep, class _Period> 166 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d); 167 template <class _Clock, class _Duration> 168 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); 169 170 void unlock(); 171 172 _LIBCPP_INLINE_VISIBILITY 173 void swap(unique_lock& __u) _NOEXCEPT 174 { 175 _VSTD::swap(__m_, __u.__m_); 176 _VSTD::swap(__owns_, __u.__owns_); 177 } 178 _LIBCPP_INLINE_VISIBILITY 179 mutex_type* release() _NOEXCEPT 180 { 181 mutex_type* __m = __m_; 182 __m_ = nullptr; 183 __owns_ = false; 184 return __m; 185 } 186 187 _LIBCPP_INLINE_VISIBILITY 188 bool owns_lock() const _NOEXCEPT {return __owns_;} 189 _LIBCPP_INLINE_VISIBILITY 190 explicit operator bool() const _NOEXCEPT {return __owns_;} 191 _LIBCPP_INLINE_VISIBILITY 192 mutex_type* mutex() const _NOEXCEPT {return __m_;} 193}; 194 195template <class _Mutex> 196void 197unique_lock<_Mutex>::lock() 198{ 199 if (__m_ == nullptr) 200 __throw_system_error(EPERM, "unique_lock::lock: references null mutex"); 201 if (__owns_) 202 __throw_system_error(EDEADLK, "unique_lock::lock: already locked"); 203 __m_->lock(); 204 __owns_ = true; 205} 206 207template <class _Mutex> 208bool 209unique_lock<_Mutex>::try_lock() 210{ 211 if (__m_ == nullptr) 212 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex"); 213 if (__owns_) 214 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked"); 215 __owns_ = __m_->try_lock(); 216 return __owns_; 217} 218 219template <class _Mutex> 220template <class _Rep, class _Period> 221bool 222unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) 223{ 224 if (__m_ == nullptr) 225 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex"); 226 if (__owns_) 227 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked"); 228 __owns_ = __m_->try_lock_for(__d); 229 return __owns_; 230} 231 232template <class _Mutex> 233template <class _Clock, class _Duration> 234bool 235unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 236{ 237 if (__m_ == nullptr) 238 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex"); 239 if (__owns_) 240 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked"); 241 __owns_ = __m_->try_lock_until(__t); 242 return __owns_; 243} 244 245template <class _Mutex> 246void 247unique_lock<_Mutex>::unlock() 248{ 249 if (!__owns_) 250 __throw_system_error(EPERM, "unique_lock::unlock: not locked"); 251 __m_->unlock(); 252 __owns_ = false; 253} 254 255template <class _Mutex> 256inline _LIBCPP_INLINE_VISIBILITY 257void 258swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT 259 {__x.swap(__y);} 260 261//enum class cv_status 262_LIBCPP_DECLARE_STRONG_ENUM(cv_status) 263{ 264 no_timeout, 265 timeout 266}; 267_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status) 268 269class _LIBCPP_TYPE_VIS condition_variable 270{ 271 __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER; 272public: 273 _LIBCPP_INLINE_VISIBILITY 274 _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default; 275 276#ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION 277 ~condition_variable() = default; 278#else 279 ~condition_variable(); 280#endif 281 282 condition_variable(const condition_variable&) = delete; 283 condition_variable& operator=(const condition_variable&) = delete; 284 285 void notify_one() _NOEXCEPT; 286 void notify_all() _NOEXCEPT; 287 288 void wait(unique_lock<mutex>& __lk) _NOEXCEPT; 289 template <class _Predicate> 290 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 291 void wait(unique_lock<mutex>& __lk, _Predicate __pred); 292 293 template <class _Clock, class _Duration> 294 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 295 cv_status 296 wait_until(unique_lock<mutex>& __lk, 297 const chrono::time_point<_Clock, _Duration>& __t); 298 299 template <class _Clock, class _Duration, class _Predicate> 300 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 301 bool 302 wait_until(unique_lock<mutex>& __lk, 303 const chrono::time_point<_Clock, _Duration>& __t, 304 _Predicate __pred); 305 306 template <class _Rep, class _Period> 307 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 308 cv_status 309 wait_for(unique_lock<mutex>& __lk, 310 const chrono::duration<_Rep, _Period>& __d); 311 312 template <class _Rep, class _Period, class _Predicate> 313 bool 314 _LIBCPP_INLINE_VISIBILITY 315 wait_for(unique_lock<mutex>& __lk, 316 const chrono::duration<_Rep, _Period>& __d, 317 _Predicate __pred); 318 319 typedef __libcpp_condvar_t* native_handle_type; 320 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;} 321 322private: 323 void __do_timed_wait(unique_lock<mutex>& __lk, 324 chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT; 325#if defined(_LIBCPP_HAS_COND_CLOCKWAIT) 326 void __do_timed_wait(unique_lock<mutex>& __lk, 327 chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT; 328#endif 329 template <class _Clock> 330 void __do_timed_wait(unique_lock<mutex>& __lk, 331 chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT; 332}; 333#endif // !_LIBCPP_HAS_NO_THREADS 334 335template <class _Rep, class _Period> 336inline _LIBCPP_INLINE_VISIBILITY 337typename enable_if 338< 339 is_floating_point<_Rep>::value, 340 chrono::nanoseconds 341>::type 342__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) 343{ 344 using namespace chrono; 345 using __ratio = ratio_divide<_Period, nano>; 346 using __ns_rep = nanoseconds::rep; 347 _Rep __result_float = __d.count() * __ratio::num / __ratio::den; 348 349 _Rep __result_max = numeric_limits<__ns_rep>::max(); 350 if (__result_float >= __result_max) { 351 return nanoseconds::max(); 352 } 353 354 _Rep __result_min = numeric_limits<__ns_rep>::min(); 355 if (__result_float <= __result_min) { 356 return nanoseconds::min(); 357 } 358 359 return nanoseconds(static_cast<__ns_rep>(__result_float)); 360} 361 362template <class _Rep, class _Period> 363inline _LIBCPP_INLINE_VISIBILITY 364typename enable_if 365< 366 !is_floating_point<_Rep>::value, 367 chrono::nanoseconds 368>::type 369__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) 370{ 371 using namespace chrono; 372 if (__d.count() == 0) { 373 return nanoseconds(0); 374 } 375 376 using __ratio = ratio_divide<_Period, nano>; 377 using __ns_rep = nanoseconds::rep; 378 __ns_rep __result_max = numeric_limits<__ns_rep>::max(); 379 if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) { 380 return nanoseconds::max(); 381 } 382 383 __ns_rep __result_min = numeric_limits<__ns_rep>::min(); 384 if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) { 385 return nanoseconds::min(); 386 } 387 388 __ns_rep __result = __d.count() * __ratio::num / __ratio::den; 389 if (__result == 0) { 390 return nanoseconds(1); 391 } 392 393 return nanoseconds(__result); 394} 395 396#ifndef _LIBCPP_HAS_NO_THREADS 397template <class _Predicate> 398void 399condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) 400{ 401 while (!__pred()) 402 wait(__lk); 403} 404 405template <class _Clock, class _Duration> 406cv_status 407condition_variable::wait_until(unique_lock<mutex>& __lk, 408 const chrono::time_point<_Clock, _Duration>& __t) 409{ 410 using namespace chrono; 411 using __clock_tp_ns = time_point<_Clock, nanoseconds>; 412 413 typename _Clock::time_point __now = _Clock::now(); 414 if (__t <= __now) 415 return cv_status::timeout; 416 417 __clock_tp_ns __t_ns = __clock_tp_ns(_VSTD::__safe_nanosecond_cast(__t.time_since_epoch())); 418 419 __do_timed_wait(__lk, __t_ns); 420 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout; 421} 422 423template <class _Clock, class _Duration, class _Predicate> 424bool 425condition_variable::wait_until(unique_lock<mutex>& __lk, 426 const chrono::time_point<_Clock, _Duration>& __t, 427 _Predicate __pred) 428{ 429 while (!__pred()) 430 { 431 if (wait_until(__lk, __t) == cv_status::timeout) 432 return __pred(); 433 } 434 return true; 435} 436 437template <class _Rep, class _Period> 438cv_status 439condition_variable::wait_for(unique_lock<mutex>& __lk, 440 const chrono::duration<_Rep, _Period>& __d) 441{ 442 using namespace chrono; 443 if (__d <= __d.zero()) 444 return cv_status::timeout; 445 using __ns_rep = nanoseconds::rep; 446 steady_clock::time_point __c_now = steady_clock::now(); 447 448#if defined(_LIBCPP_HAS_COND_CLOCKWAIT) 449 using __clock_tp_ns = time_point<steady_clock, nanoseconds>; 450 __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(__c_now.time_since_epoch()).count(); 451#else 452 using __clock_tp_ns = time_point<system_clock, nanoseconds>; 453 __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count(); 454#endif 455 456 __ns_rep __d_ns_count = _VSTD::__safe_nanosecond_cast(__d).count(); 457 458 if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) { 459 __do_timed_wait(__lk, __clock_tp_ns::max()); 460 } else { 461 __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count))); 462 } 463 464 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : 465 cv_status::timeout; 466} 467 468template <class _Rep, class _Period, class _Predicate> 469inline 470bool 471condition_variable::wait_for(unique_lock<mutex>& __lk, 472 const chrono::duration<_Rep, _Period>& __d, 473 _Predicate __pred) 474{ 475 return wait_until(__lk, chrono::steady_clock::now() + __d, 476 _VSTD::move(__pred)); 477} 478 479#if defined(_LIBCPP_HAS_COND_CLOCKWAIT) 480inline 481void 482condition_variable::__do_timed_wait(unique_lock<mutex>& __lk, 483 chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT 484{ 485 using namespace chrono; 486 if (!__lk.owns_lock()) 487 __throw_system_error(EPERM, 488 "condition_variable::timed wait: mutex not locked"); 489 nanoseconds __d = __tp.time_since_epoch(); 490 timespec __ts; 491 seconds __s = duration_cast<seconds>(__d); 492 using __ts_sec = decltype(__ts.tv_sec); 493 const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max(); 494 if (__s.count() < __ts_sec_max) 495 { 496 __ts.tv_sec = static_cast<__ts_sec>(__s.count()); 497 __ts.tv_nsec = (__d - __s).count(); 498 } 499 else 500 { 501 __ts.tv_sec = __ts_sec_max; 502 __ts.tv_nsec = giga::num - 1; 503 } 504 int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts); 505 if (__ec != 0 && __ec != ETIMEDOUT) 506 __throw_system_error(__ec, "condition_variable timed_wait failed"); 507} 508#endif // _LIBCPP_HAS_COND_CLOCKWAIT 509 510template <class _Clock> 511inline 512void 513condition_variable::__do_timed_wait(unique_lock<mutex>& __lk, 514 chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT 515{ 516 wait_for(__lk, __tp - _Clock::now()); 517} 518 519#endif // !_LIBCPP_HAS_NO_THREADS 520 521_LIBCPP_END_NAMESPACE_STD 522 523_LIBCPP_POP_MACROS 524 525#endif // _LIBCPP___MUTEX_BASE 526