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