1 // std::unique_lock implementation -*- C++ -*- 2 3 // Copyright (C) 2008-2020 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file bits/unique_lock.h 26 * This is an internal header file, included by other library headers. 27 * Do not attempt to use it directly. @headername{mutex} 28 */ 29 30 #ifndef _GLIBCXX_UNIQUE_LOCK_H 31 #define _GLIBCXX_UNIQUE_LOCK_H 1 32 33 #pragma GCC system_header 34 35 #if __cplusplus < 201103L 36 # include <bits/c++0x_warning.h> 37 #else 38 39 #include <chrono> 40 #include <bits/move.h> // for std::swap 41 42 namespace std _GLIBCXX_VISIBILITY(default) 43 { 44 _GLIBCXX_BEGIN_NAMESPACE_VERSION 45 46 /** @brief A movable scoped lock type. 47 * 48 * A unique_lock controls mutex ownership within a scope. Ownership of the 49 * mutex can be delayed until after construction and can be transferred 50 * to another unique_lock by move construction or move assignment. If a 51 * mutex lock is owned when the destructor runs ownership will be released. 52 * 53 * @ingroup mutexes 54 */ 55 template<typename _Mutex> 56 class unique_lock 57 { 58 public: 59 typedef _Mutex mutex_type; 60 61 unique_lock() noexcept 62 : _M_device(0), _M_owns(false) 63 { } 64 65 explicit unique_lock(mutex_type& __m) 66 : _M_device(std::__addressof(__m)), _M_owns(false) 67 { 68 lock(); 69 _M_owns = true; 70 } 71 72 unique_lock(mutex_type& __m, defer_lock_t) noexcept 73 : _M_device(std::__addressof(__m)), _M_owns(false) 74 { } 75 76 unique_lock(mutex_type& __m, try_to_lock_t) 77 : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock()) 78 { } 79 80 unique_lock(mutex_type& __m, adopt_lock_t) noexcept 81 : _M_device(std::__addressof(__m)), _M_owns(true) 82 { 83 // XXX calling thread owns mutex 84 } 85 86 template<typename _Clock, typename _Duration> 87 unique_lock(mutex_type& __m, 88 const chrono::time_point<_Clock, _Duration>& __atime) 89 : _M_device(std::__addressof(__m)), 90 _M_owns(_M_device->try_lock_until(__atime)) 91 { } 92 93 template<typename _Rep, typename _Period> 94 unique_lock(mutex_type& __m, 95 const chrono::duration<_Rep, _Period>& __rtime) 96 : _M_device(std::__addressof(__m)), 97 _M_owns(_M_device->try_lock_for(__rtime)) 98 { } 99 100 ~unique_lock() 101 { 102 if (_M_owns) 103 unlock(); 104 } 105 106 unique_lock(const unique_lock&) = delete; 107 unique_lock& operator=(const unique_lock&) = delete; 108 109 unique_lock(unique_lock&& __u) noexcept 110 : _M_device(__u._M_device), _M_owns(__u._M_owns) 111 { 112 __u._M_device = 0; 113 __u._M_owns = false; 114 } 115 116 unique_lock& operator=(unique_lock&& __u) noexcept 117 { 118 if(_M_owns) 119 unlock(); 120 121 unique_lock(std::move(__u)).swap(*this); 122 123 __u._M_device = 0; 124 __u._M_owns = false; 125 126 return *this; 127 } 128 129 void 130 lock() 131 { 132 if (!_M_device) 133 __throw_system_error(int(errc::operation_not_permitted)); 134 else if (_M_owns) 135 __throw_system_error(int(errc::resource_deadlock_would_occur)); 136 else 137 { 138 _M_device->lock(); 139 _M_owns = true; 140 } 141 } 142 143 bool 144 try_lock() 145 { 146 if (!_M_device) 147 __throw_system_error(int(errc::operation_not_permitted)); 148 else if (_M_owns) 149 __throw_system_error(int(errc::resource_deadlock_would_occur)); 150 else 151 { 152 _M_owns = _M_device->try_lock(); 153 return _M_owns; 154 } 155 } 156 157 template<typename _Clock, typename _Duration> 158 bool 159 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 160 { 161 if (!_M_device) 162 __throw_system_error(int(errc::operation_not_permitted)); 163 else if (_M_owns) 164 __throw_system_error(int(errc::resource_deadlock_would_occur)); 165 else 166 { 167 _M_owns = _M_device->try_lock_until(__atime); 168 return _M_owns; 169 } 170 } 171 172 template<typename _Rep, typename _Period> 173 bool 174 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 175 { 176 if (!_M_device) 177 __throw_system_error(int(errc::operation_not_permitted)); 178 else if (_M_owns) 179 __throw_system_error(int(errc::resource_deadlock_would_occur)); 180 else 181 { 182 _M_owns = _M_device->try_lock_for(__rtime); 183 return _M_owns; 184 } 185 } 186 187 void 188 unlock() 189 { 190 if (!_M_owns) 191 __throw_system_error(int(errc::operation_not_permitted)); 192 else if (_M_device) 193 { 194 _M_device->unlock(); 195 _M_owns = false; 196 } 197 } 198 199 void 200 swap(unique_lock& __u) noexcept 201 { 202 std::swap(_M_device, __u._M_device); 203 std::swap(_M_owns, __u._M_owns); 204 } 205 206 mutex_type* 207 release() noexcept 208 { 209 mutex_type* __ret = _M_device; 210 _M_device = 0; 211 _M_owns = false; 212 return __ret; 213 } 214 215 bool 216 owns_lock() const noexcept 217 { return _M_owns; } 218 219 explicit operator bool() const noexcept 220 { return owns_lock(); } 221 222 mutex_type* 223 mutex() const noexcept 224 { return _M_device; } 225 226 private: 227 mutex_type* _M_device; 228 bool _M_owns; 229 }; 230 231 /// Swap overload for unique_lock objects. 232 /// @relates unique_lock 233 template<typename _Mutex> 234 inline void 235 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept 236 { __x.swap(__y); } 237 238 _GLIBCXX_END_NAMESPACE_VERSION 239 } // namespace 240 241 #endif // C++11 242 #endif // _GLIBCXX_UNIQUE_LOCK_H 243