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