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