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