1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef _LIBCPP___MUTEX_UNIQUE_LOCK_H 10 #define _LIBCPP___MUTEX_UNIQUE_LOCK_H 11 12 #include <__chrono/duration.h> 13 #include <__chrono/time_point.h> 14 #include <__config> 15 #include <__memory/addressof.h> 16 #include <__mutex/tag_types.h> 17 #include <__system_error/system_error.h> 18 #include <__utility/swap.h> 19 #include <cerrno> 20 21 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 22 # pragma GCC system_header 23 #endif 24 25 #ifndef _LIBCPP_HAS_NO_THREADS 26 27 _LIBCPP_BEGIN_NAMESPACE_STD 28 29 template <class _Mutex> 30 class _LIBCPP_TEMPLATE_VIS unique_lock { 31 public: 32 typedef _Mutex mutex_type; 33 34 private: 35 mutex_type* __m_; 36 bool __owns_; 37 38 public: 39 _LIBCPP_HIDE_FROM_ABI unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {} 40 _LIBCPP_HIDE_FROM_ABI explicit unique_lock(mutex_type& __m) : __m_(std::addressof(__m)), __owns_(true) { 41 __m_->lock(); 42 } 43 44 _LIBCPP_HIDE_FROM_ABI unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT 45 : __m_(std::addressof(__m)), 46 __owns_(false) {} 47 48 _LIBCPP_HIDE_FROM_ABI unique_lock(mutex_type& __m, try_to_lock_t) 49 : __m_(std::addressof(__m)), __owns_(__m.try_lock()) {} 50 51 _LIBCPP_HIDE_FROM_ABI unique_lock(mutex_type& __m, adopt_lock_t) : __m_(std::addressof(__m)), __owns_(true) {} 52 53 template <class _Clock, class _Duration> 54 _LIBCPP_HIDE_FROM_ABI unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t) 55 : __m_(std::addressof(__m)), __owns_(__m.try_lock_until(__t)) {} 56 57 template <class _Rep, class _Period> 58 _LIBCPP_HIDE_FROM_ABI unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d) 59 : __m_(std::addressof(__m)), __owns_(__m.try_lock_for(__d)) {} 60 61 _LIBCPP_HIDE_FROM_ABI ~unique_lock() { 62 if (__owns_) 63 __m_->unlock(); 64 } 65 66 unique_lock(unique_lock const&) = delete; 67 unique_lock& operator=(unique_lock const&) = delete; 68 69 _LIBCPP_HIDE_FROM_ABI unique_lock(unique_lock&& __u) _NOEXCEPT : __m_(__u.__m_), __owns_(__u.__owns_) { 70 __u.__m_ = nullptr; 71 __u.__owns_ = false; 72 } 73 74 _LIBCPP_HIDE_FROM_ABI unique_lock& operator=(unique_lock&& __u) _NOEXCEPT { 75 if (__owns_) 76 __m_->unlock(); 77 78 __m_ = __u.__m_; 79 __owns_ = __u.__owns_; 80 __u.__m_ = nullptr; 81 __u.__owns_ = false; 82 return *this; 83 } 84 85 void lock(); 86 bool try_lock(); 87 88 template <class _Rep, class _Period> 89 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d); 90 91 template <class _Clock, class _Duration> 92 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); 93 94 void unlock(); 95 96 _LIBCPP_HIDE_FROM_ABI void swap(unique_lock& __u) _NOEXCEPT { 97 std::swap(__m_, __u.__m_); 98 std::swap(__owns_, __u.__owns_); 99 } 100 101 _LIBCPP_HIDE_FROM_ABI mutex_type* release() _NOEXCEPT { 102 mutex_type* __m = __m_; 103 __m_ = nullptr; 104 __owns_ = false; 105 return __m; 106 } 107 108 _LIBCPP_HIDE_FROM_ABI bool owns_lock() const _NOEXCEPT { return __owns_; } 109 _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __owns_; } 110 _LIBCPP_HIDE_FROM_ABI mutex_type* mutex() const _NOEXCEPT { return __m_; } 111 }; 112 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(unique_lock); 113 114 template <class _Mutex> 115 void unique_lock<_Mutex>::lock() { 116 if (__m_ == nullptr) 117 __throw_system_error(EPERM, "unique_lock::lock: references null mutex"); 118 if (__owns_) 119 __throw_system_error(EDEADLK, "unique_lock::lock: already locked"); 120 __m_->lock(); 121 __owns_ = true; 122 } 123 124 template <class _Mutex> 125 bool unique_lock<_Mutex>::try_lock() { 126 if (__m_ == nullptr) 127 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex"); 128 if (__owns_) 129 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked"); 130 __owns_ = __m_->try_lock(); 131 return __owns_; 132 } 133 134 template <class _Mutex> 135 template <class _Rep, class _Period> 136 bool unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) { 137 if (__m_ == nullptr) 138 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex"); 139 if (__owns_) 140 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked"); 141 __owns_ = __m_->try_lock_for(__d); 142 return __owns_; 143 } 144 145 template <class _Mutex> 146 template <class _Clock, class _Duration> 147 bool unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { 148 if (__m_ == nullptr) 149 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex"); 150 if (__owns_) 151 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked"); 152 __owns_ = __m_->try_lock_until(__t); 153 return __owns_; 154 } 155 156 template <class _Mutex> 157 void unique_lock<_Mutex>::unlock() { 158 if (!__owns_) 159 __throw_system_error(EPERM, "unique_lock::unlock: not locked"); 160 __m_->unlock(); 161 __owns_ = false; 162 } 163 164 template <class _Mutex> 165 inline _LIBCPP_HIDE_FROM_ABI void swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT { 166 __x.swap(__y); 167 } 168 169 _LIBCPP_END_NAMESPACE_STD 170 171 #endif // _LIBCPP_HAS_NO_THREADS 172 173 #endif // _LIBCPP___MUTEX_UNIQUE_LOCK_H 174