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