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