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