1// -*- C++ -*- 2//===----------------------------------------------------------------------===// 3// 4// The LLVM Compiler Infrastructure 5// 6// This file is dual licensed under the MIT and the University of Illinois Open 7// Source Licenses. See LICENSE.TXT for details. 8// 9//===----------------------------------------------------------------------===// 10 11#ifndef _LIBCPP___MUTEX_BASE 12#define _LIBCPP___MUTEX_BASE 13 14#include <__config> 15#include <chrono> 16#include <system_error> 17#include <__threading_support> 18 19#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 20#pragma GCC system_header 21#endif 22 23_LIBCPP_BEGIN_NAMESPACE_STD 24 25#ifndef _LIBCPP_HAS_NO_THREADS 26 27#ifndef _LIBCPP_THREAD_SAFETY_ANNOTATION 28# ifdef _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS 29# define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x)) 30# else 31# define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) 32# endif 33#endif // _LIBCPP_THREAD_SAFETY_ANNOTATION 34 35class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex 36{ 37 __libcpp_mutex_t __m_; 38 39public: 40 _LIBCPP_INLINE_VISIBILITY 41#ifndef _LIBCPP_HAS_NO_CONSTEXPR 42 constexpr mutex() _NOEXCEPT : __m_(_LIBCPP_MUTEX_INITIALIZER) {} 43#else 44 mutex() _NOEXCEPT {__m_ = (__libcpp_mutex_t)_LIBCPP_MUTEX_INITIALIZER;} 45#endif 46 ~mutex(); 47 48private: 49 mutex(const mutex&);// = delete; 50 mutex& operator=(const mutex&);// = delete; 51 52public: 53 void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); 54 bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true)); 55 void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()); 56 57 typedef __libcpp_mutex_t* native_handle_type; 58 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;} 59}; 60 61struct _LIBCPP_TYPE_VIS defer_lock_t {}; 62struct _LIBCPP_TYPE_VIS try_to_lock_t {}; 63struct _LIBCPP_TYPE_VIS adopt_lock_t {}; 64 65#if defined(_LIBCPP_HAS_NO_CONSTEXPR) || defined(_LIBCPP_BUILDING_MUTEX) 66 67extern const defer_lock_t defer_lock; 68extern const try_to_lock_t try_to_lock; 69extern const adopt_lock_t adopt_lock; 70 71#else 72 73constexpr defer_lock_t defer_lock = defer_lock_t(); 74constexpr try_to_lock_t try_to_lock = try_to_lock_t(); 75constexpr adopt_lock_t adopt_lock = adopt_lock_t(); 76 77#endif 78 79 80// Forward declare lock_guard as a variadic template even in C++03 to keep 81// the mangling consistent between dialects. 82#if defined(_LIBCPP_ABI_VARIADIC_LOCK_GUARD) 83template <class ..._Mutexes> 84class _LIBCPP_TYPE_VIS_ONLY lock_guard; 85#endif 86 87template <class _Mutex> 88class _LIBCPP_TYPE_VIS_ONLY _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) 89#if !defined(_LIBCPP_ABI_VARIADIC_LOCK_GUARD) 90lock_guard 91#else 92lock_guard<_Mutex> 93#endif 94{ 95public: 96 typedef _Mutex mutex_type; 97 98private: 99 mutex_type& __m_; 100public: 101 102 _LIBCPP_INLINE_VISIBILITY 103 explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) 104 : __m_(__m) {__m_.lock();} 105 _LIBCPP_INLINE_VISIBILITY 106 lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m)) 107 : __m_(__m) {} 108 _LIBCPP_INLINE_VISIBILITY 109 ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();} 110 111private: 112 lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE; 113 lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE; 114}; 115 116template <class _Mutex> 117class _LIBCPP_TYPE_VIS_ONLY unique_lock 118{ 119public: 120 typedef _Mutex mutex_type; 121 122private: 123 mutex_type* __m_; 124 bool __owns_; 125 126public: 127 _LIBCPP_INLINE_VISIBILITY 128 unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {} 129 _LIBCPP_INLINE_VISIBILITY 130 explicit unique_lock(mutex_type& __m) 131 : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();} 132 _LIBCPP_INLINE_VISIBILITY 133 unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT 134 : __m_(_VSTD::addressof(__m)), __owns_(false) {} 135 _LIBCPP_INLINE_VISIBILITY 136 unique_lock(mutex_type& __m, try_to_lock_t) 137 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {} 138 _LIBCPP_INLINE_VISIBILITY 139 unique_lock(mutex_type& __m, adopt_lock_t) 140 : __m_(_VSTD::addressof(__m)), __owns_(true) {} 141 template <class _Clock, class _Duration> 142 _LIBCPP_INLINE_VISIBILITY 143 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t) 144 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {} 145 template <class _Rep, class _Period> 146 _LIBCPP_INLINE_VISIBILITY 147 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d) 148 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {} 149 _LIBCPP_INLINE_VISIBILITY 150 ~unique_lock() 151 { 152 if (__owns_) 153 __m_->unlock(); 154 } 155 156private: 157 unique_lock(unique_lock const&); // = delete; 158 unique_lock& operator=(unique_lock const&); // = delete; 159 160public: 161#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES 162 _LIBCPP_INLINE_VISIBILITY 163 unique_lock(unique_lock&& __u) _NOEXCEPT 164 : __m_(__u.__m_), __owns_(__u.__owns_) 165 {__u.__m_ = nullptr; __u.__owns_ = false;} 166 _LIBCPP_INLINE_VISIBILITY 167 unique_lock& operator=(unique_lock&& __u) _NOEXCEPT 168 { 169 if (__owns_) 170 __m_->unlock(); 171 __m_ = __u.__m_; 172 __owns_ = __u.__owns_; 173 __u.__m_ = nullptr; 174 __u.__owns_ = false; 175 return *this; 176 } 177 178#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES 179 180 void lock(); 181 bool try_lock(); 182 183 template <class _Rep, class _Period> 184 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d); 185 template <class _Clock, class _Duration> 186 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); 187 188 void unlock(); 189 190 _LIBCPP_INLINE_VISIBILITY 191 void swap(unique_lock& __u) _NOEXCEPT 192 { 193 _VSTD::swap(__m_, __u.__m_); 194 _VSTD::swap(__owns_, __u.__owns_); 195 } 196 _LIBCPP_INLINE_VISIBILITY 197 mutex_type* release() _NOEXCEPT 198 { 199 mutex_type* __m = __m_; 200 __m_ = nullptr; 201 __owns_ = false; 202 return __m; 203 } 204 205 _LIBCPP_INLINE_VISIBILITY 206 bool owns_lock() const _NOEXCEPT {return __owns_;} 207 _LIBCPP_INLINE_VISIBILITY 208 _LIBCPP_EXPLICIT 209 operator bool () const _NOEXCEPT {return __owns_;} 210 _LIBCPP_INLINE_VISIBILITY 211 mutex_type* mutex() const _NOEXCEPT {return __m_;} 212}; 213 214template <class _Mutex> 215void 216unique_lock<_Mutex>::lock() 217{ 218 if (__m_ == nullptr) 219 __throw_system_error(EPERM, "unique_lock::lock: references null mutex"); 220 if (__owns_) 221 __throw_system_error(EDEADLK, "unique_lock::lock: already locked"); 222 __m_->lock(); 223 __owns_ = true; 224} 225 226template <class _Mutex> 227bool 228unique_lock<_Mutex>::try_lock() 229{ 230 if (__m_ == nullptr) 231 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex"); 232 if (__owns_) 233 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked"); 234 __owns_ = __m_->try_lock(); 235 return __owns_; 236} 237 238template <class _Mutex> 239template <class _Rep, class _Period> 240bool 241unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) 242{ 243 if (__m_ == nullptr) 244 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex"); 245 if (__owns_) 246 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked"); 247 __owns_ = __m_->try_lock_for(__d); 248 return __owns_; 249} 250 251template <class _Mutex> 252template <class _Clock, class _Duration> 253bool 254unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 255{ 256 if (__m_ == nullptr) 257 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex"); 258 if (__owns_) 259 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked"); 260 __owns_ = __m_->try_lock_until(__t); 261 return __owns_; 262} 263 264template <class _Mutex> 265void 266unique_lock<_Mutex>::unlock() 267{ 268 if (!__owns_) 269 __throw_system_error(EPERM, "unique_lock::unlock: not locked"); 270 __m_->unlock(); 271 __owns_ = false; 272} 273 274template <class _Mutex> 275inline _LIBCPP_INLINE_VISIBILITY 276void 277swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT 278 {__x.swap(__y);} 279 280//enum class cv_status 281_LIBCPP_DECLARE_STRONG_ENUM(cv_status) 282{ 283 no_timeout, 284 timeout 285}; 286_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status) 287 288class _LIBCPP_TYPE_VIS condition_variable 289{ 290 __libcpp_condvar_t __cv_; 291public: 292 _LIBCPP_INLINE_VISIBILITY 293#ifndef _LIBCPP_HAS_NO_CONSTEXPR 294 constexpr condition_variable() : __cv_(_LIBCPP_CONDVAR_INITIALIZER) {} 295#else 296 condition_variable() {__cv_ = (__libcpp_condvar_t)_LIBCPP_CONDVAR_INITIALIZER;} 297#endif 298 ~condition_variable(); 299 300private: 301 condition_variable(const condition_variable&); // = delete; 302 condition_variable& operator=(const condition_variable&); // = delete; 303 304public: 305 void notify_one() _NOEXCEPT; 306 void notify_all() _NOEXCEPT; 307 308 void wait(unique_lock<mutex>& __lk) _NOEXCEPT; 309 template <class _Predicate> 310 void wait(unique_lock<mutex>& __lk, _Predicate __pred); 311 312 template <class _Clock, class _Duration> 313 cv_status 314 wait_until(unique_lock<mutex>& __lk, 315 const chrono::time_point<_Clock, _Duration>& __t); 316 317 template <class _Clock, class _Duration, class _Predicate> 318 bool 319 wait_until(unique_lock<mutex>& __lk, 320 const chrono::time_point<_Clock, _Duration>& __t, 321 _Predicate __pred); 322 323 template <class _Rep, class _Period> 324 cv_status 325 wait_for(unique_lock<mutex>& __lk, 326 const chrono::duration<_Rep, _Period>& __d); 327 328 template <class _Rep, class _Period, class _Predicate> 329 bool 330 _LIBCPP_INLINE_VISIBILITY 331 wait_for(unique_lock<mutex>& __lk, 332 const chrono::duration<_Rep, _Period>& __d, 333 _Predicate __pred); 334 335 typedef __libcpp_condvar_t* native_handle_type; 336 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;} 337 338private: 339 void __do_timed_wait(unique_lock<mutex>& __lk, 340 chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT; 341}; 342#endif // !_LIBCPP_HAS_NO_THREADS 343 344template <class _To, class _Rep, class _Period> 345inline _LIBCPP_INLINE_VISIBILITY 346typename enable_if 347< 348 chrono::__is_duration<_To>::value, 349 _To 350>::type 351__ceil(chrono::duration<_Rep, _Period> __d) 352{ 353 using namespace chrono; 354 _To __r = duration_cast<_To>(__d); 355 if (__r < __d) 356 ++__r; 357 return __r; 358} 359 360#ifndef _LIBCPP_HAS_NO_THREADS 361template <class _Predicate> 362void 363condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) 364{ 365 while (!__pred()) 366 wait(__lk); 367} 368 369template <class _Clock, class _Duration> 370cv_status 371condition_variable::wait_until(unique_lock<mutex>& __lk, 372 const chrono::time_point<_Clock, _Duration>& __t) 373{ 374 using namespace chrono; 375 wait_for(__lk, __t - _Clock::now()); 376 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout; 377} 378 379template <class _Clock, class _Duration, class _Predicate> 380bool 381condition_variable::wait_until(unique_lock<mutex>& __lk, 382 const chrono::time_point<_Clock, _Duration>& __t, 383 _Predicate __pred) 384{ 385 while (!__pred()) 386 { 387 if (wait_until(__lk, __t) == cv_status::timeout) 388 return __pred(); 389 } 390 return true; 391} 392 393template <class _Rep, class _Period> 394cv_status 395condition_variable::wait_for(unique_lock<mutex>& __lk, 396 const chrono::duration<_Rep, _Period>& __d) 397{ 398 using namespace chrono; 399 if (__d <= __d.zero()) 400 return cv_status::timeout; 401 typedef time_point<system_clock, duration<long double, nano> > __sys_tpf; 402 typedef time_point<system_clock, nanoseconds> __sys_tpi; 403 __sys_tpf _Max = __sys_tpi::max(); 404 system_clock::time_point __s_now = system_clock::now(); 405 steady_clock::time_point __c_now = steady_clock::now(); 406 if (_Max - __d > __s_now) 407 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d)); 408 else 409 __do_timed_wait(__lk, __sys_tpi::max()); 410 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : 411 cv_status::timeout; 412} 413 414template <class _Rep, class _Period, class _Predicate> 415inline 416bool 417condition_variable::wait_for(unique_lock<mutex>& __lk, 418 const chrono::duration<_Rep, _Period>& __d, 419 _Predicate __pred) 420{ 421 return wait_until(__lk, chrono::steady_clock::now() + __d, 422 _VSTD::move(__pred)); 423} 424 425#endif // !_LIBCPP_HAS_NO_THREADS 426 427_LIBCPP_END_NAMESPACE_STD 428 429#endif // _LIBCPP___MUTEX_BASE 430