1 // std::unique_lock implementation -*- C++ -*- 2 3 // Copyright (C) 2008-2019 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 /** 47 * @ingroup mutexes 48 * @{ 49 */ 50 51 /** @brief A movable scoped lock type. 52 * 53 * A unique_lock controls mutex ownership within a scope. Ownership of the 54 * mutex can be delayed until after construction and can be transferred 55 * to another unique_lock by move construction or move assignment. If a 56 * mutex lock is owned when the destructor runs ownership will be released. 57 */ 58 template<typename _Mutex> 59 class unique_lock 60 { 61 public: 62 typedef _Mutex mutex_type; 63 64 unique_lock() noexcept 65 : _M_device(0), _M_owns(false) 66 { } 67 68 explicit unique_lock(mutex_type& __m) 69 : _M_device(std::__addressof(__m)), _M_owns(false) 70 { 71 lock(); 72 _M_owns = true; 73 } 74 75 unique_lock(mutex_type& __m, defer_lock_t) noexcept 76 : _M_device(std::__addressof(__m)), _M_owns(false) 77 { } 78 79 unique_lock(mutex_type& __m, try_to_lock_t) 80 : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock()) 81 { } 82 83 unique_lock(mutex_type& __m, adopt_lock_t) noexcept 84 : _M_device(std::__addressof(__m)), _M_owns(true) 85 { 86 // XXX calling thread owns mutex 87 } 88 89 template<typename _Clock, typename _Duration> 90 unique_lock(mutex_type& __m, 91 const chrono::time_point<_Clock, _Duration>& __atime) 92 : _M_device(std::__addressof(__m)), 93 _M_owns(_M_device->try_lock_until(__atime)) 94 { } 95 96 template<typename _Rep, typename _Period> 97 unique_lock(mutex_type& __m, 98 const chrono::duration<_Rep, _Period>& __rtime) 99 : _M_device(std::__addressof(__m)), 100 _M_owns(_M_device->try_lock_for(__rtime)) 101 { } 102 103 ~unique_lock() 104 { 105 if (_M_owns) 106 unlock(); 107 } 108 109 unique_lock(const unique_lock&) = delete; 110 unique_lock& operator=(const unique_lock&) = delete; 111 112 unique_lock(unique_lock&& __u) noexcept 113 : _M_device(__u._M_device), _M_owns(__u._M_owns) 114 { 115 __u._M_device = 0; 116 __u._M_owns = false; 117 } 118 119 unique_lock& operator=(unique_lock&& __u) noexcept 120 { 121 if(_M_owns) 122 unlock(); 123 124 unique_lock(std::move(__u)).swap(*this); 125 126 __u._M_device = 0; 127 __u._M_owns = false; 128 129 return *this; 130 } 131 132 void 133 lock() 134 { 135 if (!_M_device) 136 __throw_system_error(int(errc::operation_not_permitted)); 137 else if (_M_owns) 138 __throw_system_error(int(errc::resource_deadlock_would_occur)); 139 else 140 { 141 _M_device->lock(); 142 _M_owns = true; 143 } 144 } 145 146 bool 147 try_lock() 148 { 149 if (!_M_device) 150 __throw_system_error(int(errc::operation_not_permitted)); 151 else if (_M_owns) 152 __throw_system_error(int(errc::resource_deadlock_would_occur)); 153 else 154 { 155 _M_owns = _M_device->try_lock(); 156 return _M_owns; 157 } 158 } 159 160 template<typename _Clock, typename _Duration> 161 bool 162 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 163 { 164 if (!_M_device) 165 __throw_system_error(int(errc::operation_not_permitted)); 166 else if (_M_owns) 167 __throw_system_error(int(errc::resource_deadlock_would_occur)); 168 else 169 { 170 _M_owns = _M_device->try_lock_until(__atime); 171 return _M_owns; 172 } 173 } 174 175 template<typename _Rep, typename _Period> 176 bool 177 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 178 { 179 if (!_M_device) 180 __throw_system_error(int(errc::operation_not_permitted)); 181 else if (_M_owns) 182 __throw_system_error(int(errc::resource_deadlock_would_occur)); 183 else 184 { 185 _M_owns = _M_device->try_lock_for(__rtime); 186 return _M_owns; 187 } 188 } 189 190 void 191 unlock() 192 { 193 if (!_M_owns) 194 __throw_system_error(int(errc::operation_not_permitted)); 195 else if (_M_device) 196 { 197 _M_device->unlock(); 198 _M_owns = false; 199 } 200 } 201 202 void 203 swap(unique_lock& __u) noexcept 204 { 205 std::swap(_M_device, __u._M_device); 206 std::swap(_M_owns, __u._M_owns); 207 } 208 209 mutex_type* 210 release() noexcept 211 { 212 mutex_type* __ret = _M_device; 213 _M_device = 0; 214 _M_owns = false; 215 return __ret; 216 } 217 218 bool 219 owns_lock() const noexcept 220 { return _M_owns; } 221 222 explicit operator bool() const noexcept 223 { return owns_lock(); } 224 225 mutex_type* 226 mutex() const noexcept 227 { return _M_device; } 228 229 private: 230 mutex_type* _M_device; 231 bool _M_owns; 232 }; 233 234 /// Swap overload for unique_lock objects. 235 template<typename _Mutex> 236 inline void 237 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept 238 { __x.swap(__y); } 239 240 // @} group mutexes 241 _GLIBCXX_END_NAMESPACE_VERSION 242 } // namespace 243 244 #endif // C++11 245 #endif // _GLIBCXX_UNIQUE_LOCK_H 246