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