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