]>
Commit | Line | Data |
---|---|---|
68a97d24 BK |
1 | // <mutex> -*- C++ -*- |
2 | ||
818ab71a | 3 | // Copyright (C) 2003-2016 Free Software Foundation, Inc. |
68a97d24 BK |
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 | |
748086b7 | 8 | // Free Software Foundation; either version 3, or (at your option) |
68a97d24 BK |
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 | ||
748086b7 JJ |
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. | |
68a97d24 | 19 | |
748086b7 JJ |
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/>. | |
68a97d24 | 24 | |
f910786b | 25 | /** @file include/mutex |
68a97d24 BK |
26 | * This is a Standard C++ Library header. |
27 | */ | |
28 | ||
29 | #ifndef _GLIBCXX_MUTEX | |
30 | #define _GLIBCXX_MUTEX 1 | |
31 | ||
32 | #pragma GCC system_header | |
33 | ||
734f5023 | 34 | #if __cplusplus < 201103L |
ab65a4c7 | 35 | # include <bits/c++0x_warning.h> |
57317d2a | 36 | #else |
68a97d24 | 37 | |
57cb79ef | 38 | #include <tuple> |
7b800287 CF |
39 | #include <chrono> |
40 | #include <exception> | |
41 | #include <type_traits> | |
7b800287 | 42 | #include <system_error> |
0c3e5dd1 | 43 | #include <bits/std_mutex.h> |
f16081c2 JW |
44 | #if ! _GTHREAD_USE_MUTEX_TIMEDLOCK |
45 | # include <condition_variable> | |
46 | # include <thread> | |
47 | #endif | |
d67dd0be JW |
48 | #ifndef _GLIBCXX_HAVE_TLS |
49 | # include <functional> | |
50 | #endif | |
7b800287 | 51 | |
3442f18d | 52 | #ifdef _GLIBCXX_USE_C99_STDINT_TR1 |
68a97d24 | 53 | |
12ffa228 BK |
54 | namespace std _GLIBCXX_VISIBILITY(default) |
55 | { | |
56 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
53dc5044 | 57 | |
f16081c2 JW |
58 | /** |
59 | * @ingroup mutexes | |
60 | * @{ | |
61 | */ | |
b81e920e | 62 | |
f16081c2 | 63 | #ifdef _GLIBCXX_HAS_GTHREADS |
b81e920e | 64 | |
d872e4aa | 65 | // Common base class for std::recursive_mutex and std::recursive_timed_mutex |
b81e920e JW |
66 | class __recursive_mutex_base |
67 | { | |
68 | protected: | |
69 | typedef __gthread_recursive_mutex_t __native_type; | |
70 | ||
71 | __recursive_mutex_base(const __recursive_mutex_base&) = delete; | |
72 | __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete; | |
73 | ||
74 | #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT | |
75 | __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; | |
76 | ||
77 | __recursive_mutex_base() = default; | |
78 | #else | |
79 | __native_type _M_mutex; | |
80 | ||
81 | __recursive_mutex_base() | |
82 | { | |
83 | // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) | |
84 | __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); | |
85 | } | |
86 | ||
87 | ~__recursive_mutex_base() | |
1504e3e1 | 88 | { __gthread_recursive_mutex_destroy(&_M_mutex); } |
b81e920e JW |
89 | #endif |
90 | }; | |
91 | ||
6b4f8906 | 92 | /// The standard recursive mutex type. |
b81e920e | 93 | class recursive_mutex : private __recursive_mutex_base |
68a97d24 BK |
94 | { |
95 | public: | |
f7459b6c | 96 | typedef __native_type* native_handle_type; |
68a97d24 | 97 | |
b81e920e JW |
98 | recursive_mutex() = default; |
99 | ~recursive_mutex() = default; | |
9916a9e4 | 100 | |
7b800287 CF |
101 | recursive_mutex(const recursive_mutex&) = delete; |
102 | recursive_mutex& operator=(const recursive_mutex&) = delete; | |
103 | ||
4db6bc0f | 104 | void |
68a97d24 | 105 | lock() |
4db6bc0f | 106 | { |
68a97d24 BK |
107 | int __e = __gthread_recursive_mutex_lock(&_M_mutex); |
108 | ||
109 | // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) | |
d3098c94 CF |
110 | if (__e) |
111 | __throw_system_error(__e); | |
68a97d24 | 112 | } |
4db6bc0f BK |
113 | |
114 | bool | |
7f0d79d5 | 115 | try_lock() noexcept |
68a97d24 | 116 | { |
22ac021b | 117 | // XXX EINVAL, EAGAIN, EBUSY |
7b800287 | 118 | return !__gthread_recursive_mutex_trylock(&_M_mutex); |
68a97d24 BK |
119 | } |
120 | ||
4db6bc0f | 121 | void |
68a97d24 | 122 | unlock() |
4db6bc0f | 123 | { |
22ac021b | 124 | // XXX EINVAL, EAGAIN, EBUSY |
7b800287 | 125 | __gthread_recursive_mutex_unlock(&_M_mutex); |
68a97d24 BK |
126 | } |
127 | ||
4db6bc0f | 128 | native_handle_type |
2c15eace | 129 | native_handle() noexcept |
7b800287 | 130 | { return &_M_mutex; } |
68a97d24 BK |
131 | }; |
132 | ||
3b2eeb43 | 133 | #if _GTHREAD_USE_MUTEX_TIMEDLOCK |
25e00ab6 JW |
134 | template<typename _Derived> |
135 | class __timed_mutex_impl | |
136 | { | |
137 | protected: | |
25e00ab6 | 138 | typedef chrono::high_resolution_clock __clock_t; |
f7459b6c | 139 | |
25e00ab6 JW |
140 | template<typename _Rep, typename _Period> |
141 | bool | |
142 | _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) | |
143 | { | |
61622399 JW |
144 | using chrono::steady_clock; |
145 | auto __rt = chrono::duration_cast<steady_clock::duration>(__rtime); | |
146 | if (ratio_greater<steady_clock::period, _Period>()) | |
25e00ab6 | 147 | ++__rt; |
61622399 | 148 | return _M_try_lock_until(steady_clock::now() + __rt); |
25e00ab6 JW |
149 | } |
150 | ||
151 | template<typename _Duration> | |
152 | bool | |
153 | _M_try_lock_until(const chrono::time_point<__clock_t, | |
154 | _Duration>& __atime) | |
155 | { | |
61622399 JW |
156 | auto __s = chrono::time_point_cast<chrono::seconds>(__atime); |
157 | auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); | |
25e00ab6 JW |
158 | |
159 | __gthread_time_t __ts = { | |
160 | static_cast<std::time_t>(__s.time_since_epoch().count()), | |
161 | static_cast<long>(__ns.count()) | |
162 | }; | |
163 | ||
d8e19f31 | 164 | return static_cast<_Derived*>(this)->_M_timedlock(__ts); |
25e00ab6 JW |
165 | } |
166 | ||
167 | template<typename _Clock, typename _Duration> | |
168 | bool | |
169 | _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) | |
61622399 JW |
170 | { |
171 | auto __rtime = __atime - _Clock::now(); | |
172 | return _M_try_lock_until(__clock_t::now() + __rtime); | |
173 | } | |
25e00ab6 JW |
174 | }; |
175 | ||
6b4f8906 | 176 | /// The standard timed mutex type. |
25e00ab6 JW |
177 | class timed_mutex |
178 | : private __mutex_base, public __timed_mutex_impl<timed_mutex> | |
179 | { | |
d3098c94 | 180 | public: |
f7459b6c | 181 | typedef __native_type* native_handle_type; |
d3098c94 | 182 | |
b81e920e JW |
183 | timed_mutex() = default; |
184 | ~timed_mutex() = default; | |
9916a9e4 | 185 | |
7b800287 CF |
186 | timed_mutex(const timed_mutex&) = delete; |
187 | timed_mutex& operator=(const timed_mutex&) = delete; | |
188 | ||
189 | void | |
190 | lock() | |
191 | { | |
192 | int __e = __gthread_mutex_lock(&_M_mutex); | |
193 | ||
194 | // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) | |
195 | if (__e) | |
196 | __throw_system_error(__e); | |
197 | } | |
198 | ||
199 | bool | |
7f0d79d5 | 200 | try_lock() noexcept |
7b800287 CF |
201 | { |
202 | // XXX EINVAL, EAGAIN, EBUSY | |
203 | return !__gthread_mutex_trylock(&_M_mutex); | |
204 | } | |
d3098c94 CF |
205 | |
206 | template <class _Rep, class _Period> | |
207 | bool | |
7b800287 | 208 | try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) |
25e00ab6 | 209 | { return _M_try_lock_for(__rtime); } |
d3098c94 CF |
210 | |
211 | template <class _Clock, class _Duration> | |
212 | bool | |
7b800287 | 213 | try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) |
25e00ab6 | 214 | { return _M_try_lock_until(__atime); } |
7b800287 CF |
215 | |
216 | void | |
217 | unlock() | |
218 | { | |
219 | // XXX EINVAL, EAGAIN, EBUSY | |
220 | __gthread_mutex_unlock(&_M_mutex); | |
221 | } | |
d3098c94 CF |
222 | |
223 | native_handle_type | |
2c15eace | 224 | native_handle() noexcept |
7b800287 | 225 | { return &_M_mutex; } |
d8e19f31 SH |
226 | |
227 | private: | |
228 | friend class __timed_mutex_impl<timed_mutex>; | |
229 | ||
230 | bool | |
231 | _M_timedlock(const __gthread_time_t& __ts) | |
232 | { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); } | |
d3098c94 CF |
233 | }; |
234 | ||
235 | /// recursive_timed_mutex | |
25e00ab6 JW |
236 | class recursive_timed_mutex |
237 | : private __recursive_mutex_base, | |
238 | public __timed_mutex_impl<recursive_timed_mutex> | |
d3098c94 CF |
239 | { |
240 | public: | |
f7459b6c | 241 | typedef __native_type* native_handle_type; |
7b800287 | 242 | |
b81e920e JW |
243 | recursive_timed_mutex() = default; |
244 | ~recursive_timed_mutex() = default; | |
9916a9e4 | 245 | |
7b800287 CF |
246 | recursive_timed_mutex(const recursive_timed_mutex&) = delete; |
247 | recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; | |
248 | ||
249 | void | |
250 | lock() | |
251 | { | |
252 | int __e = __gthread_recursive_mutex_lock(&_M_mutex); | |
253 | ||
254 | // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) | |
255 | if (__e) | |
256 | __throw_system_error(__e); | |
257 | } | |
d3098c94 | 258 | |
7b800287 | 259 | bool |
7f0d79d5 | 260 | try_lock() noexcept |
7b800287 CF |
261 | { |
262 | // XXX EINVAL, EAGAIN, EBUSY | |
263 | return !__gthread_recursive_mutex_trylock(&_M_mutex); | |
264 | } | |
d3098c94 CF |
265 | |
266 | template <class _Rep, class _Period> | |
267 | bool | |
7b800287 | 268 | try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) |
25e00ab6 | 269 | { return _M_try_lock_for(__rtime); } |
d3098c94 CF |
270 | |
271 | template <class _Clock, class _Duration> | |
272 | bool | |
7b800287 | 273 | try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) |
25e00ab6 | 274 | { return _M_try_lock_until(__atime); } |
7b800287 CF |
275 | |
276 | void | |
277 | unlock() | |
278 | { | |
279 | // XXX EINVAL, EAGAIN, EBUSY | |
280 | __gthread_recursive_mutex_unlock(&_M_mutex); | |
281 | } | |
d3098c94 CF |
282 | |
283 | native_handle_type | |
2c15eace | 284 | native_handle() noexcept |
7b800287 | 285 | { return &_M_mutex; } |
d8e19f31 SH |
286 | |
287 | private: | |
288 | friend class __timed_mutex_impl<recursive_timed_mutex>; | |
289 | ||
290 | bool | |
291 | _M_timedlock(const __gthread_time_t& __ts) | |
292 | { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); } | |
d3098c94 | 293 | }; |
68a97d24 | 294 | |
f16081c2 | 295 | #else // !_GTHREAD_USE_MUTEX_TIMEDLOCK |
68a97d24 | 296 | |
f16081c2 JW |
297 | /// timed_mutex |
298 | class timed_mutex | |
299 | { | |
300 | mutex _M_mut; | |
301 | condition_variable _M_cv; | |
302 | bool _M_locked = false; | |
68a97d24 | 303 | |
f16081c2 | 304 | public: |
68a97d24 | 305 | |
f16081c2 | 306 | timed_mutex() = default; |
2f1e8e7c | 307 | ~timed_mutex() { __glibcxx_assert( !_M_locked ); } |
7b800287 | 308 | |
f16081c2 JW |
309 | timed_mutex(const timed_mutex&) = delete; |
310 | timed_mutex& operator=(const timed_mutex&) = delete; | |
68a97d24 | 311 | |
f16081c2 JW |
312 | void |
313 | lock() | |
68a97d24 | 314 | { |
f16081c2 JW |
315 | unique_lock<mutex> __lk(_M_mut); |
316 | _M_cv.wait(__lk, [&]{ return !_M_locked; }); | |
317 | _M_locked = true; | |
318 | } | |
f7459b6c | 319 | |
f16081c2 JW |
320 | bool |
321 | try_lock() | |
322 | { | |
323 | lock_guard<mutex> __lk(_M_mut); | |
324 | if (_M_locked) | |
325 | return false; | |
326 | _M_locked = true; | |
327 | return true; | |
328 | } | |
68a97d24 | 329 | |
f16081c2 JW |
330 | template<typename _Rep, typename _Period> |
331 | bool | |
332 | try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) | |
4db6bc0f | 333 | { |
f16081c2 JW |
334 | unique_lock<mutex> __lk(_M_mut); |
335 | if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; })) | |
336 | return false; | |
337 | _M_locked = true; | |
338 | return true; | |
68a97d24 | 339 | } |
4db6bc0f | 340 | |
f16081c2 JW |
341 | template<typename _Clock, typename _Duration> |
342 | bool | |
343 | try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) | |
68a97d24 | 344 | { |
f16081c2 JW |
345 | unique_lock<mutex> __lk(_M_mut); |
346 | if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; })) | |
347 | return false; | |
348 | _M_locked = true; | |
349 | return true; | |
68a97d24 BK |
350 | } |
351 | ||
f16081c2 JW |
352 | void |
353 | unlock() | |
354 | { | |
355 | lock_guard<mutex> __lk(_M_mut); | |
2f1e8e7c | 356 | __glibcxx_assert( _M_locked ); |
f16081c2 JW |
357 | _M_locked = false; |
358 | _M_cv.notify_one(); | |
359 | } | |
360 | }; | |
68a97d24 | 361 | |
f16081c2 JW |
362 | /// recursive_timed_mutex |
363 | class recursive_timed_mutex | |
364 | { | |
365 | mutex _M_mut; | |
366 | condition_variable _M_cv; | |
367 | thread::id _M_owner; | |
368 | unsigned _M_count = 0; | |
68a97d24 | 369 | |
f16081c2 JW |
370 | // Predicate type that tests whether the current thread can lock a mutex. |
371 | struct _Can_lock | |
372 | { | |
f16081c2 JW |
373 | // Returns true if the mutex is unlocked or is locked by _M_caller. |
374 | bool | |
375 | operator()() const noexcept | |
376 | { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; } | |
7b800287 | 377 | |
f16081c2 JW |
378 | const recursive_timed_mutex* _M_mx; |
379 | thread::id _M_caller; | |
380 | }; | |
7b800287 | 381 | |
f16081c2 | 382 | public: |
f7459b6c | 383 | |
f16081c2 | 384 | recursive_timed_mutex() = default; |
2f1e8e7c | 385 | ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); } |
68a97d24 | 386 | |
f16081c2 JW |
387 | recursive_timed_mutex(const recursive_timed_mutex&) = delete; |
388 | recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; | |
f7459b6c | 389 | |
f16081c2 JW |
390 | void |
391 | lock() | |
392 | { | |
c79c59f0 JW |
393 | auto __id = this_thread::get_id(); |
394 | _Can_lock __can_lock{this, __id}; | |
f16081c2 JW |
395 | unique_lock<mutex> __lk(_M_mut); |
396 | _M_cv.wait(__lk, __can_lock); | |
397 | if (_M_count == -1u) | |
398 | __throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3 | |
399 | _M_owner = __id; | |
400 | ++_M_count; | |
401 | } | |
402 | ||
403 | bool | |
404 | try_lock() | |
405 | { | |
c79c59f0 JW |
406 | auto __id = this_thread::get_id(); |
407 | _Can_lock __can_lock{this, __id}; | |
f16081c2 JW |
408 | lock_guard<mutex> __lk(_M_mut); |
409 | if (!__can_lock()) | |
410 | return false; | |
411 | if (_M_count == -1u) | |
412 | return false; | |
413 | _M_owner = __id; | |
414 | ++_M_count; | |
415 | return true; | |
416 | } | |
68a97d24 | 417 | |
f16081c2 JW |
418 | template<typename _Rep, typename _Period> |
419 | bool | |
420 | try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) | |
4db6bc0f | 421 | { |
c79c59f0 JW |
422 | auto __id = this_thread::get_id(); |
423 | _Can_lock __can_lock{this, __id}; | |
f16081c2 | 424 | unique_lock<mutex> __lk(_M_mut); |
c79c59f0 | 425 | if (!_M_cv.wait_for(__lk, __rtime, __can_lock)) |
f16081c2 JW |
426 | return false; |
427 | if (_M_count == -1u) | |
428 | return false; | |
429 | _M_owner = __id; | |
430 | ++_M_count; | |
431 | return true; | |
68a97d24 BK |
432 | } |
433 | ||
f16081c2 | 434 | template<typename _Clock, typename _Duration> |
4db6bc0f | 435 | bool |
f16081c2 | 436 | try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) |
4db6bc0f | 437 | { |
c79c59f0 JW |
438 | auto __id = this_thread::get_id(); |
439 | _Can_lock __can_lock{this, __id}; | |
f16081c2 | 440 | unique_lock<mutex> __lk(_M_mut); |
c79c59f0 | 441 | if (!_M_cv.wait_until(__lk, __atime, __can_lock)) |
f16081c2 JW |
442 | return false; |
443 | if (_M_count == -1u) | |
444 | return false; | |
445 | _M_owner = __id; | |
446 | ++_M_count; | |
447 | return true; | |
68a97d24 BK |
448 | } |
449 | ||
f16081c2 JW |
450 | void |
451 | unlock() | |
452 | { | |
453 | lock_guard<mutex> __lk(_M_mut); | |
2f1e8e7c JW |
454 | __glibcxx_assert( _M_owner == this_thread::get_id() ); |
455 | __glibcxx_assert( _M_count > 0 ); | |
f16081c2 | 456 | if (--_M_count == 0) |
f7459b6c | 457 | { |
f16081c2 JW |
458 | _M_owner = {}; |
459 | _M_cv.notify_one(); | |
7b800287 | 460 | } |
f16081c2 JW |
461 | } |
462 | }; | |
f7459b6c | 463 | |
f16081c2 JW |
464 | #endif |
465 | #endif // _GLIBCXX_HAS_GTHREADS | |
68a97d24 | 466 | |
9b2b801a | 467 | template<typename _Lock> |
b82f988e | 468 | inline unique_lock<_Lock> |
9b2b801a | 469 | __try_to_lock(_Lock& __l) |
b82f988e | 470 | { return unique_lock<_Lock>{__l, try_to_lock}; } |
9b2b801a | 471 | |
57cb79ef CF |
472 | template<int _Idx, bool _Continue = true> |
473 | struct __try_lock_impl | |
474 | { | |
475 | template<typename... _Lock> | |
9b2b801a JW |
476 | static void |
477 | __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) | |
f7459b6c | 478 | { |
9b2b801a | 479 | __idx = _Idx; |
b82f988e | 480 | auto __lock = std::__try_to_lock(std::get<_Idx>(__locks)); |
9b2b801a JW |
481 | if (__lock.owns_lock()) |
482 | { | |
b82f988e JW |
483 | constexpr bool __cont = _Idx + 2 < sizeof...(_Lock); |
484 | using __try_locker = __try_lock_impl<_Idx + 1, __cont>; | |
485 | __try_locker::__do_try_lock(__locks, __idx); | |
9b2b801a JW |
486 | if (__idx == -1) |
487 | __lock.release(); | |
488 | } | |
57cb79ef CF |
489 | } |
490 | }; | |
f7459b6c | 491 | |
57cb79ef CF |
492 | template<int _Idx> |
493 | struct __try_lock_impl<_Idx, false> | |
494 | { | |
495 | template<typename... _Lock> | |
9b2b801a JW |
496 | static void |
497 | __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) | |
f7459b6c | 498 | { |
9b2b801a | 499 | __idx = _Idx; |
b82f988e | 500 | auto __lock = std::__try_to_lock(std::get<_Idx>(__locks)); |
9b2b801a JW |
501 | if (__lock.owns_lock()) |
502 | { | |
503 | __idx = -1; | |
504 | __lock.release(); | |
505 | } | |
57cb79ef CF |
506 | } |
507 | }; | |
f7459b6c | 508 | |
57cb79ef CF |
509 | /** @brief Generic try_lock. |
510 | * @param __l1 Meets Mutex requirements (try_lock() may throw). | |
511 | * @param __l2 Meets Mutex requirements (try_lock() may throw). | |
512 | * @param __l3 Meets Mutex requirements (try_lock() may throw). | |
f7459b6c | 513 | * @return Returns -1 if all try_lock() calls return true. Otherwise returns |
57cb79ef CF |
514 | * a 0-based index corresponding to the argument that returned false. |
515 | * @post Either all arguments are locked, or none will be. | |
516 | * | |
517 | * Sequentially calls try_lock() on each argument. | |
518 | */ | |
519 | template<typename _Lock1, typename _Lock2, typename... _Lock3> | |
4db6bc0f | 520 | int |
57cb79ef CF |
521 | try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3) |
522 | { | |
9b2b801a JW |
523 | int __idx; |
524 | auto __locks = std::tie(__l1, __l2, __l3...); | |
726d3136 | 525 | __try_lock_impl<0>::__do_try_lock(__locks, __idx); |
9b2b801a | 526 | return __idx; |
57cb79ef | 527 | } |
68a97d24 | 528 | |
9b2b801a JW |
529 | /** @brief Generic lock. |
530 | * @param __l1 Meets Mutex requirements (try_lock() may throw). | |
531 | * @param __l2 Meets Mutex requirements (try_lock() may throw). | |
532 | * @param __l3 Meets Mutex requirements (try_lock() may throw). | |
533 | * @throw An exception thrown by an argument's lock() or try_lock() member. | |
534 | * @post All arguments are locked. | |
535 | * | |
536 | * All arguments are locked via a sequence of calls to lock(), try_lock() | |
537 | * and unlock(). If the call exits via an exception any locks that were | |
538 | * obtained will be released. | |
539 | */ | |
b82f988e | 540 | template<typename _L1, typename _L2, typename... _L3> |
4db6bc0f | 541 | void |
9b2b801a JW |
542 | lock(_L1& __l1, _L2& __l2, _L3&... __l3) |
543 | { | |
544 | while (true) | |
545 | { | |
b82f988e | 546 | using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>; |
9b2b801a JW |
547 | unique_lock<_L1> __first(__l1); |
548 | int __idx; | |
549 | auto __locks = std::tie(__l2, __l3...); | |
b82f988e | 550 | __try_locker::__do_try_lock(__locks, __idx); |
9b2b801a JW |
551 | if (__idx == -1) |
552 | { | |
553 | __first.release(); | |
554 | return; | |
555 | } | |
556 | } | |
557 | } | |
68a97d24 | 558 | |
3442f18d | 559 | #ifdef _GLIBCXX_HAS_GTHREADS |
68a97d24 | 560 | /// once_flag |
4db6bc0f | 561 | struct once_flag |
68a97d24 | 562 | { |
f7459b6c | 563 | private: |
68a97d24 | 564 | typedef __gthread_once_t __native_type; |
eed33268 | 565 | __native_type _M_once = __GTHREAD_ONCE_INIT; |
68a97d24 | 566 | |
f7459b6c | 567 | public: |
e06745c1 | 568 | /// Constructor |
eed33268 | 569 | constexpr once_flag() noexcept = default; |
f7459b6c | 570 | |
e06745c1 | 571 | /// Deleted copy constructor |
7b800287 | 572 | once_flag(const once_flag&) = delete; |
e06745c1 | 573 | /// Deleted assignment operator |
7b800287 | 574 | once_flag& operator=(const once_flag&) = delete; |
68a97d24 | 575 | |
7b800287 CF |
576 | template<typename _Callable, typename... _Args> |
577 | friend void | |
1b3fad81 | 578 | call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); |
68a97d24 BK |
579 | }; |
580 | ||
7b800287 CF |
581 | #ifdef _GLIBCXX_HAVE_TLS |
582 | extern __thread void* __once_callable; | |
583 | extern __thread void (*__once_call)(); | |
7b800287 CF |
584 | #else |
585 | extern function<void()> __once_functor; | |
99827523 | 586 | |
efdb7347 JW |
587 | extern void |
588 | __set_once_functor_lock_ptr(unique_lock<mutex>*); | |
589 | ||
590 | extern mutex& | |
591 | __get_once_mutex(); | |
7b800287 CF |
592 | #endif |
593 | ||
ff02a38b | 594 | extern "C" void __once_proxy(void); |
7b800287 | 595 | |
5b9daa7e | 596 | /// call_once |
68a97d24 | 597 | template<typename _Callable, typename... _Args> |
4db6bc0f | 598 | void |
1b3fad81 | 599 | call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) |
68a97d24 | 600 | { |
164b41eb JW |
601 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
602 | // 2442. call_once() shouldn't DECAY_COPY() | |
cfbdc34f | 603 | auto __callable = [&] { |
164b41eb JW |
604 | std::__invoke(std::forward<_Callable>(__f), |
605 | std::forward<_Args>(__args)...); | |
606 | }; | |
cfbdc34f JW |
607 | #ifdef _GLIBCXX_HAVE_TLS |
608 | __once_callable = std::__addressof(__callable); | |
609 | __once_call = []{ (*(decltype(__callable)*)__once_callable)(); }; | |
610 | #else | |
611 | unique_lock<mutex> __functor_lock(__get_once_mutex()); | |
612 | __once_functor = __callable; | |
efdb7347 | 613 | __set_once_functor_lock_ptr(&__functor_lock); |
7b800287 | 614 | #endif |
f7459b6c | 615 | |
bd24ec2d | 616 | int __e = __gthread_once(&__once._M_once, &__once_proxy); |
7b800287 | 617 | |
cca36d72 PC |
618 | #ifndef _GLIBCXX_HAVE_TLS |
619 | if (__functor_lock) | |
efdb7347 | 620 | __set_once_functor_lock_ptr(0); |
cca36d72 PC |
621 | #endif |
622 | ||
4db6bc0f | 623 | if (__e) |
68a97d24 BK |
624 | __throw_system_error(__e); |
625 | } | |
3442f18d | 626 | #endif // _GLIBCXX_HAS_GTHREADS |
5b9daa7e BK |
627 | |
628 | // @} group mutexes | |
12ffa228 BK |
629 | _GLIBCXX_END_NAMESPACE_VERSION |
630 | } // namespace | |
3442f18d | 631 | #endif // _GLIBCXX_USE_C99_STDINT_TR1 |
7b800287 | 632 | |
734f5023 | 633 | #endif // C++11 |
68a97d24 | 634 | |
57317d2a | 635 | #endif // _GLIBCXX_MUTEX |