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 79template <class _Mutex> 80class _LIBCPP_TYPE_VIS_ONLY _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) lock_guard 81{ 82public: 83 typedef _Mutex mutex_type; 84 85private: 86 mutex_type& __m_; 87public: 88 89 _LIBCPP_INLINE_VISIBILITY 90 explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) 91 : __m_(__m) {__m_.lock();} 92 _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&);// = delete; 100 lock_guard& operator=(lock_guard const&);// = delete; 101}; 102 103template <class _Mutex> 104class _LIBCPP_TYPE_VIS_ONLY 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#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES 149 _LIBCPP_INLINE_VISIBILITY 150 unique_lock(unique_lock&& __u) _NOEXCEPT 151 : __m_(__u.__m_), __owns_(__u.__owns_) 152 {__u.__m_ = nullptr; __u.__owns_ = false;} 153 _LIBCPP_INLINE_VISIBILITY 154 unique_lock& operator=(unique_lock&& __u) _NOEXCEPT 155 { 156 if (__owns_) 157 __m_->unlock(); 158 __m_ = __u.__m_; 159 __owns_ = __u.__owns_; 160 __u.__m_ = nullptr; 161 __u.__owns_ = false; 162 return *this; 163 } 164 165#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES 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 _LIBCPP_EXPLICIT 196 operator bool () const _NOEXCEPT {return __owns_;} 197 _LIBCPP_INLINE_VISIBILITY 198 mutex_type* mutex() const _NOEXCEPT {return __m_;} 199}; 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_; 278public: 279 _LIBCPP_INLINE_VISIBILITY 280#ifndef _LIBCPP_HAS_NO_CONSTEXPR 281 constexpr condition_variable() : __cv_(_LIBCPP_CONDVAR_INITIALIZER) {} 282#else 283 condition_variable() {__cv_ = (__libcpp_condvar_t)_LIBCPP_CONDVAR_INITIALIZER;} 284#endif 285 ~condition_variable(); 286 287private: 288 condition_variable(const condition_variable&); // = delete; 289 condition_variable& operator=(const condition_variable&); // = delete; 290 291public: 292 void notify_one() _NOEXCEPT; 293 void notify_all() _NOEXCEPT; 294 295 void wait(unique_lock<mutex>& __lk) _NOEXCEPT; 296 template <class _Predicate> 297 void wait(unique_lock<mutex>& __lk, _Predicate __pred); 298 299 template <class _Clock, class _Duration> 300 cv_status 301 wait_until(unique_lock<mutex>& __lk, 302 const chrono::time_point<_Clock, _Duration>& __t); 303 304 template <class _Clock, class _Duration, class _Predicate> 305 bool 306 wait_until(unique_lock<mutex>& __lk, 307 const chrono::time_point<_Clock, _Duration>& __t, 308 _Predicate __pred); 309 310 template <class _Rep, class _Period> 311 cv_status 312 wait_for(unique_lock<mutex>& __lk, 313 const chrono::duration<_Rep, _Period>& __d); 314 315 template <class _Rep, class _Period, class _Predicate> 316 bool 317 _LIBCPP_INLINE_VISIBILITY 318 wait_for(unique_lock<mutex>& __lk, 319 const chrono::duration<_Rep, _Period>& __d, 320 _Predicate __pred); 321 322 typedef __libcpp_condvar_t* native_handle_type; 323 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;} 324 325private: 326 void __do_timed_wait(unique_lock<mutex>& __lk, 327 chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT; 328}; 329#endif // !_LIBCPP_HAS_NO_THREADS 330 331template <class _To, class _Rep, class _Period> 332inline _LIBCPP_INLINE_VISIBILITY 333typename enable_if 334< 335 chrono::__is_duration<_To>::value, 336 _To 337>::type 338__ceil(chrono::duration<_Rep, _Period> __d) 339{ 340 using namespace chrono; 341 _To __r = duration_cast<_To>(__d); 342 if (__r < __d) 343 ++__r; 344 return __r; 345} 346 347#ifndef _LIBCPP_HAS_NO_THREADS 348template <class _Predicate> 349void 350condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) 351{ 352 while (!__pred()) 353 wait(__lk); 354} 355 356template <class _Clock, class _Duration> 357cv_status 358condition_variable::wait_until(unique_lock<mutex>& __lk, 359 const chrono::time_point<_Clock, _Duration>& __t) 360{ 361 using namespace chrono; 362 wait_for(__lk, __t - _Clock::now()); 363 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout; 364} 365 366template <class _Clock, class _Duration, class _Predicate> 367bool 368condition_variable::wait_until(unique_lock<mutex>& __lk, 369 const chrono::time_point<_Clock, _Duration>& __t, 370 _Predicate __pred) 371{ 372 while (!__pred()) 373 { 374 if (wait_until(__lk, __t) == cv_status::timeout) 375 return __pred(); 376 } 377 return true; 378} 379 380template <class _Rep, class _Period> 381cv_status 382condition_variable::wait_for(unique_lock<mutex>& __lk, 383 const chrono::duration<_Rep, _Period>& __d) 384{ 385 using namespace chrono; 386 if (__d <= __d.zero()) 387 return cv_status::timeout; 388 typedef time_point<system_clock, duration<long double, nano> > __sys_tpf; 389 typedef time_point<system_clock, nanoseconds> __sys_tpi; 390 __sys_tpf _Max = __sys_tpi::max(); 391 system_clock::time_point __s_now = system_clock::now(); 392 steady_clock::time_point __c_now = steady_clock::now(); 393 if (_Max - __d > __s_now) 394 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d)); 395 else 396 __do_timed_wait(__lk, __sys_tpi::max()); 397 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : 398 cv_status::timeout; 399} 400 401template <class _Rep, class _Period, class _Predicate> 402inline 403bool 404condition_variable::wait_for(unique_lock<mutex>& __lk, 405 const chrono::duration<_Rep, _Period>& __d, 406 _Predicate __pred) 407{ 408 return wait_until(__lk, chrono::steady_clock::now() + __d, 409 _VSTD::move(__pred)); 410} 411 412#endif // !_LIBCPP_HAS_NO_THREADS 413 414_LIBCPP_END_NAMESPACE_STD 415 416#endif // _LIBCPP___MUTEX_BASE 417