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