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 | |