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#pragma GCC system_header 20 21#ifdef _LIBCPP_SHARED_LOCK 22 23namespace ting { 24template <class> class shared_lock; 25template <class> class upgrade_lock; 26} 27 28#endif // _LIBCPP_SHARED_LOCK 29 30 31_LIBCPP_BEGIN_NAMESPACE_STD 32 33class _LIBCPP_VISIBLE mutex 34{ 35 pthread_mutex_t __m_; 36 37public: 38 _LIBCPP_INLINE_VISIBILITY 39 mutex() {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;} 40 ~mutex(); 41 42private: 43 mutex(const mutex&);// = delete; 44 mutex& operator=(const mutex&);// = delete; 45 46public: 47 void lock(); 48 bool try_lock(); 49 void unlock(); 50 51 typedef pthread_mutex_t* native_handle_type; 52 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;} 53}; 54 55struct _LIBCPP_VISIBLE defer_lock_t {}; 56struct _LIBCPP_VISIBLE try_to_lock_t {}; 57struct _LIBCPP_VISIBLE adopt_lock_t {}; 58 59//constexpr 60extern const 61defer_lock_t defer_lock; 62 63//constexpr 64extern const 65try_to_lock_t try_to_lock; 66 67//constexpr 68extern const 69adopt_lock_t adopt_lock; 70 71template <class _Mutex> 72class _LIBCPP_VISIBLE lock_guard 73{ 74public: 75 typedef _Mutex mutex_type; 76 77private: 78 mutex_type& __m_; 79public: 80 81 _LIBCPP_INLINE_VISIBILITY 82 explicit lock_guard(mutex_type& __m) 83 : __m_(__m) {__m_.lock();} 84 _LIBCPP_INLINE_VISIBILITY 85 lock_guard(mutex_type& __m, adopt_lock_t) 86 : __m_(__m) {} 87 _LIBCPP_INLINE_VISIBILITY 88 ~lock_guard() {__m_.unlock();} 89 90private: 91 lock_guard(lock_guard const&);// = delete; 92 lock_guard& operator=(lock_guard const&);// = delete; 93}; 94 95template <class _Mutex> 96class _LIBCPP_VISIBLE unique_lock 97{ 98public: 99 typedef _Mutex mutex_type; 100 101private: 102 mutex_type* __m_; 103 bool __owns_; 104 105public: 106 _LIBCPP_INLINE_VISIBILITY 107 unique_lock() : __m_(nullptr), __owns_(false) {} 108 _LIBCPP_INLINE_VISIBILITY 109 explicit unique_lock(mutex_type& __m) 110 : __m_(&__m), __owns_(true) {__m_->lock();} 111 _LIBCPP_INLINE_VISIBILITY 112 unique_lock(mutex_type& __m, defer_lock_t) 113 : __m_(&__m), __owns_(false) {} 114 _LIBCPP_INLINE_VISIBILITY 115 unique_lock(mutex_type& __m, try_to_lock_t) 116 : __m_(&__m), __owns_(__m.try_lock()) {} 117 _LIBCPP_INLINE_VISIBILITY 118 unique_lock(mutex_type& __m, adopt_lock_t) 119 : __m_(&__m), __owns_(true) {} 120 template <class _Clock, class _Duration> 121 _LIBCPP_INLINE_VISIBILITY 122 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t) 123 : __m_(&__m), __owns_(__m.try_lock_until(__t)) {} 124 template <class _Rep, class _Period> 125 _LIBCPP_INLINE_VISIBILITY 126 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d) 127 : __m_(&__m), __owns_(__m.try_lock_for(__d)) {} 128 _LIBCPP_INLINE_VISIBILITY 129 ~unique_lock() 130 { 131 if (__owns_) 132 __m_->unlock(); 133 } 134 135private: 136 unique_lock(unique_lock const&); // = delete; 137 unique_lock& operator=(unique_lock const&); // = delete; 138 139public: 140#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES 141 _LIBCPP_INLINE_VISIBILITY 142 unique_lock(unique_lock&& __u) 143 : __m_(__u.__m_), __owns_(__u.__owns_) 144 {__u.__m_ = nullptr; __u.__owns_ = false;} 145 _LIBCPP_INLINE_VISIBILITY 146 unique_lock& operator=(unique_lock&& __u) 147 { 148 if (__owns_) 149 __m_->unlock(); 150 __m_ = __u.__m_; 151 __owns_ = __u.__owns_; 152 __u.__m_ = nullptr; 153 __u.__owns_ = false; 154 return *this; 155 } 156 157#ifdef _LIBCPP_SHARED_LOCK 158 159 unique_lock(ting::shared_lock<mutex_type>&&, try_to_lock_t); 160 template <class _Clock, class _Duration> 161 unique_lock(ting::shared_lock<mutex_type>&&, 162 const chrono::time_point<_Clock, _Duration>&); 163 template <class _Rep, class _Period> 164 unique_lock(ting::shared_lock<mutex_type>&&, 165 const chrono::duration<_Rep, _Period>&); 166 167 explicit unique_lock(ting::upgrade_lock<mutex_type>&&); 168 unique_lock(ting::upgrade_lock<mutex_type>&&, try_to_lock_t); 169 template <class _Clock, class _Duration> 170 unique_lock(ting::upgrade_lock<mutex_type>&&, 171 const chrono::time_point<_Clock, _Duration>&); 172 template <class _Rep, class _Period> 173 unique_lock(ting::upgrade_lock<mutex_type>&&, 174 const chrono::duration<_Rep, _Period>&); 175 176#endif // _LIBCPP_SHARED_LOCK 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) 192 { 193 _STD::swap(__m_, __u.__m_); 194 _STD::swap(__owns_, __u.__owns_); 195 } 196 _LIBCPP_INLINE_VISIBILITY 197 mutex_type* release() 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 {return __owns_;} 207 _LIBCPP_INLINE_VISIBILITY 208// explicit 209 operator bool () const {return __owns_;} 210 _LIBCPP_INLINE_VISIBILITY 211 mutex_type* mutex() const {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) {__x.swap(__y);} 278 279struct _LIBCPP_VISIBLE cv_status 280{ 281 enum _ { 282 no_timeout, 283 timeout 284 }; 285 286 _ __v_; 287 288 _LIBCPP_INLINE_VISIBILITY cv_status(_ __v) : __v_(__v) {} 289 _LIBCPP_INLINE_VISIBILITY operator int() const {return __v_;} 290 291}; 292 293class _LIBCPP_VISIBLE condition_variable 294{ 295 pthread_cond_t __cv_; 296public: 297 _LIBCPP_INLINE_VISIBILITY 298 condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;} 299 ~condition_variable(); 300 301private: 302 condition_variable(const condition_variable&); // = delete; 303 condition_variable& operator=(const condition_variable&); // = delete; 304 305public: 306 void notify_one(); 307 void notify_all(); 308 309 void wait(unique_lock<mutex>& __lk); 310 template <class _Predicate> 311 void wait(unique_lock<mutex>& __lk, _Predicate __pred); 312 313 template <class _Duration> 314 cv_status 315 wait_until(unique_lock<mutex>& __lk, 316 const chrono::time_point<chrono::system_clock, _Duration>& __t); 317 318 template <class _Clock, class _Duration> 319 cv_status 320 wait_until(unique_lock<mutex>& __lk, 321 const chrono::time_point<_Clock, _Duration>& __t); 322 323 template <class _Clock, class _Duration, class _Predicate> 324 bool 325 wait_until(unique_lock<mutex>& __lk, 326 const chrono::time_point<_Clock, _Duration>& __t, 327 _Predicate __pred); 328 329 template <class _Rep, class _Period> 330 cv_status 331 wait_for(unique_lock<mutex>& __lk, 332 const chrono::duration<_Rep, _Period>& __d); 333 334 template <class _Rep, class _Period, class _Predicate> 335 bool 336 wait_for(unique_lock<mutex>& __lk, 337 const chrono::duration<_Rep, _Period>& __d, 338 _Predicate __pred); 339 340 typedef pthread_cond_t* native_handle_type; 341 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;} 342 343private: 344 void __do_timed_wait(unique_lock<mutex>& __lk, 345 chrono::time_point<chrono::system_clock, chrono::nanoseconds>); 346}; 347 348template <class _To, class _Rep, class _Period> 349inline _LIBCPP_INLINE_VISIBILITY 350typename enable_if 351< 352 chrono::__is_duration<_To>::value, 353 _To 354>::type 355__ceil(chrono::duration<_Rep, _Period> __d) 356{ 357 using namespace chrono; 358 _To __r = duration_cast<_To>(__d); 359 if (__r < __d) 360 ++__r; 361 return __r; 362} 363 364template <class _Predicate> 365void 366condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) 367{ 368 while (!__pred()) 369 wait(__lk); 370} 371 372template <class _Duration> 373cv_status 374condition_variable::wait_until(unique_lock<mutex>& __lk, 375 const chrono::time_point<chrono::system_clock, _Duration>& __t) 376{ 377 using namespace chrono; 378 typedef time_point<system_clock, nanoseconds> __nano_sys_tmpt; 379 __do_timed_wait(__lk, 380 __nano_sys_tmpt(__ceil<nanoseconds>(__t.time_since_epoch()))); 381 return system_clock::now() < __t ? cv_status::no_timeout : 382 cv_status::timeout; 383} 384 385template <class _Clock, class _Duration> 386cv_status 387condition_variable::wait_until(unique_lock<mutex>& __lk, 388 const chrono::time_point<_Clock, _Duration>& __t) 389{ 390 using namespace chrono; 391 system_clock::time_point __s_now = system_clock::now(); 392 typename _Clock::time_point __c_now = _Clock::now(); 393 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__t - __c_now)); 394 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout; 395} 396 397template <class _Clock, class _Duration, class _Predicate> 398bool 399condition_variable::wait_until(unique_lock<mutex>& __lk, 400 const chrono::time_point<_Clock, _Duration>& __t, 401 _Predicate __pred) 402{ 403 while (!__pred()) 404 { 405 if (wait_until(__lk, __t) == cv_status::timeout) 406 return __pred(); 407 } 408 return true; 409} 410 411template <class _Rep, class _Period> 412cv_status 413condition_variable::wait_for(unique_lock<mutex>& __lk, 414 const chrono::duration<_Rep, _Period>& __d) 415{ 416 using namespace chrono; 417 system_clock::time_point __s_now = system_clock::now(); 418 steady_clock::time_point __c_now = steady_clock::now(); 419 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d)); 420 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : 421 cv_status::timeout; 422} 423 424template <class _Rep, class _Period, class _Predicate> 425inline _LIBCPP_INLINE_VISIBILITY 426bool 427condition_variable::wait_for(unique_lock<mutex>& __lk, 428 const chrono::duration<_Rep, _Period>& __d, 429 _Predicate __pred) 430{ 431 return wait_until(__lk, chrono::steady_clock::now() + __d, 432 _STD::move(__pred)); 433} 434 435_LIBCPP_END_NAMESPACE_STD 436 437#endif // _LIBCPP___MUTEX_BASE 438