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