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