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