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