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