1 1.1 mrg // <mutex> -*- C++ -*- 2 1.1 mrg 3 1.12 mrg // Copyright (C) 2003-2022 Free Software Foundation, Inc. 4 1.1 mrg // 5 1.1 mrg // This file is part of the GNU ISO C++ Library. This library is free 6 1.1 mrg // software; you can redistribute it and/or modify it under the 7 1.1 mrg // terms of the GNU General Public License as published by the 8 1.1 mrg // Free Software Foundation; either version 3, or (at your option) 9 1.1 mrg // any later version. 10 1.1 mrg 11 1.1 mrg // This library is distributed in the hope that it will be useful, 12 1.1 mrg // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 1.1 mrg // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 1.1 mrg // GNU General Public License for more details. 15 1.1 mrg 16 1.1 mrg // Under Section 7 of GPL version 3, you are granted additional 17 1.1 mrg // permissions described in the GCC Runtime Library Exception, version 18 1.1 mrg // 3.1, as published by the Free Software Foundation. 19 1.1 mrg 20 1.1 mrg // You should have received a copy of the GNU General Public License and 21 1.1 mrg // a copy of the GCC Runtime Library Exception along with this program; 22 1.1 mrg // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 1.1 mrg // <http://www.gnu.org/licenses/>. 24 1.1 mrg 25 1.3 mrg /** @file include/mutex 26 1.1 mrg * This is a Standard C++ Library header. 27 1.1 mrg */ 28 1.1 mrg 29 1.1 mrg #ifndef _GLIBCXX_MUTEX 30 1.1 mrg #define _GLIBCXX_MUTEX 1 31 1.1 mrg 32 1.1 mrg #pragma GCC system_header 33 1.1 mrg 34 1.3 mrg #if __cplusplus < 201103L 35 1.1 mrg # include <bits/c++0x_warning.h> 36 1.1 mrg #else 37 1.1 mrg 38 1.1 mrg #include <tuple> 39 1.1 mrg #include <exception> 40 1.1 mrg #include <type_traits> 41 1.1 mrg #include <system_error> 42 1.12 mrg #include <bits/chrono.h> 43 1.6 mrg #include <bits/std_mutex.h> 44 1.10 mrg #include <bits/unique_lock.h> 45 1.6 mrg #if ! _GTHREAD_USE_MUTEX_TIMEDLOCK 46 1.6 mrg # include <condition_variable> 47 1.6 mrg # include <thread> 48 1.6 mrg #endif 49 1.12 mrg #include <ext/atomicity.h> // __gnu_cxx::__is_single_threaded 50 1.12 mrg 51 1.12 mrg #if defined _GLIBCXX_HAS_GTHREADS && ! defined _GLIBCXX_HAVE_TLS 52 1.12 mrg # include <bits/std_function.h> // std::function 53 1.8 mrg #endif 54 1.1 mrg 55 1.3 mrg namespace std _GLIBCXX_VISIBILITY(default) 56 1.1 mrg { 57 1.3 mrg _GLIBCXX_BEGIN_NAMESPACE_VERSION 58 1.3 mrg 59 1.6 mrg /** 60 1.11 mrg * @addtogroup mutexes 61 1.6 mrg * @{ 62 1.6 mrg */ 63 1.6 mrg 64 1.3 mrg #ifdef _GLIBCXX_HAS_GTHREADS 65 1.12 mrg /// @cond undocumented 66 1.3 mrg 67 1.5 mrg // Common base class for std::recursive_mutex and std::recursive_timed_mutex 68 1.3 mrg class __recursive_mutex_base 69 1.3 mrg { 70 1.3 mrg protected: 71 1.3 mrg typedef __gthread_recursive_mutex_t __native_type; 72 1.3 mrg 73 1.3 mrg __recursive_mutex_base(const __recursive_mutex_base&) = delete; 74 1.3 mrg __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete; 75 1.3 mrg 76 1.3 mrg #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT 77 1.3 mrg __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 78 1.3 mrg 79 1.3 mrg __recursive_mutex_base() = default; 80 1.3 mrg #else 81 1.3 mrg __native_type _M_mutex; 82 1.3 mrg 83 1.3 mrg __recursive_mutex_base() 84 1.3 mrg { 85 1.3 mrg // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 86 1.3 mrg __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 87 1.3 mrg } 88 1.3 mrg 89 1.3 mrg ~__recursive_mutex_base() 90 1.3 mrg { __gthread_recursive_mutex_destroy(&_M_mutex); } 91 1.3 mrg #endif 92 1.3 mrg }; 93 1.12 mrg /// @endcond 94 1.3 mrg 95 1.12 mrg /** The standard recursive mutex type. 96 1.12 mrg * 97 1.12 mrg * A recursive mutex can be locked more than once by the same thread. 98 1.12 mrg * Other threads cannot lock the mutex until the owning thread unlocks it 99 1.12 mrg * as many times as it was locked. 100 1.12 mrg * 101 1.12 mrg * @headerfile mutex 102 1.12 mrg * @since C++11 103 1.12 mrg */ 104 1.3 mrg class recursive_mutex : private __recursive_mutex_base 105 1.1 mrg { 106 1.1 mrg public: 107 1.1 mrg typedef __native_type* native_handle_type; 108 1.1 mrg 109 1.3 mrg recursive_mutex() = default; 110 1.3 mrg ~recursive_mutex() = default; 111 1.1 mrg 112 1.1 mrg recursive_mutex(const recursive_mutex&) = delete; 113 1.1 mrg recursive_mutex& operator=(const recursive_mutex&) = delete; 114 1.1 mrg 115 1.1 mrg void 116 1.1 mrg lock() 117 1.1 mrg { 118 1.1 mrg int __e = __gthread_recursive_mutex_lock(&_M_mutex); 119 1.1 mrg 120 1.1 mrg // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 121 1.1 mrg if (__e) 122 1.1 mrg __throw_system_error(__e); 123 1.1 mrg } 124 1.1 mrg 125 1.1 mrg bool 126 1.3 mrg try_lock() noexcept 127 1.1 mrg { 128 1.1 mrg // XXX EINVAL, EAGAIN, EBUSY 129 1.1 mrg return !__gthread_recursive_mutex_trylock(&_M_mutex); 130 1.1 mrg } 131 1.1 mrg 132 1.1 mrg void 133 1.1 mrg unlock() 134 1.1 mrg { 135 1.1 mrg // XXX EINVAL, EAGAIN, EBUSY 136 1.1 mrg __gthread_recursive_mutex_unlock(&_M_mutex); 137 1.1 mrg } 138 1.1 mrg 139 1.1 mrg native_handle_type 140 1.8 mrg native_handle() noexcept 141 1.1 mrg { return &_M_mutex; } 142 1.1 mrg }; 143 1.1 mrg 144 1.3 mrg #if _GTHREAD_USE_MUTEX_TIMEDLOCK 145 1.12 mrg /// @cond undocumented 146 1.12 mrg 147 1.5 mrg template<typename _Derived> 148 1.5 mrg class __timed_mutex_impl 149 1.5 mrg { 150 1.5 mrg protected: 151 1.5 mrg template<typename _Rep, typename _Period> 152 1.5 mrg bool 153 1.5 mrg _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 154 1.5 mrg { 155 1.11 mrg #if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK 156 1.11 mrg using __clock = chrono::steady_clock; 157 1.11 mrg #else 158 1.11 mrg using __clock = chrono::system_clock; 159 1.11 mrg #endif 160 1.11 mrg 161 1.11 mrg auto __rt = chrono::duration_cast<__clock::duration>(__rtime); 162 1.11 mrg if (ratio_greater<__clock::period, _Period>()) 163 1.5 mrg ++__rt; 164 1.11 mrg return _M_try_lock_until(__clock::now() + __rt); 165 1.5 mrg } 166 1.5 mrg 167 1.5 mrg template<typename _Duration> 168 1.5 mrg bool 169 1.11 mrg _M_try_lock_until(const chrono::time_point<chrono::system_clock, 170 1.5 mrg _Duration>& __atime) 171 1.5 mrg { 172 1.5 mrg auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 173 1.5 mrg auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 174 1.5 mrg 175 1.5 mrg __gthread_time_t __ts = { 176 1.5 mrg static_cast<std::time_t>(__s.time_since_epoch().count()), 177 1.5 mrg static_cast<long>(__ns.count()) 178 1.5 mrg }; 179 1.5 mrg 180 1.6 mrg return static_cast<_Derived*>(this)->_M_timedlock(__ts); 181 1.5 mrg } 182 1.5 mrg 183 1.11 mrg #ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK 184 1.11 mrg template<typename _Duration> 185 1.11 mrg bool 186 1.11 mrg _M_try_lock_until(const chrono::time_point<chrono::steady_clock, 187 1.11 mrg _Duration>& __atime) 188 1.11 mrg { 189 1.11 mrg auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 190 1.11 mrg auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 191 1.11 mrg 192 1.11 mrg __gthread_time_t __ts = { 193 1.11 mrg static_cast<std::time_t>(__s.time_since_epoch().count()), 194 1.11 mrg static_cast<long>(__ns.count()) 195 1.11 mrg }; 196 1.11 mrg 197 1.11 mrg return static_cast<_Derived*>(this)->_M_clocklock(CLOCK_MONOTONIC, 198 1.11 mrg __ts); 199 1.11 mrg } 200 1.11 mrg #endif 201 1.11 mrg 202 1.5 mrg template<typename _Clock, typename _Duration> 203 1.5 mrg bool 204 1.5 mrg _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 205 1.5 mrg { 206 1.11 mrg #if __cplusplus > 201703L 207 1.11 mrg static_assert(chrono::is_clock_v<_Clock>); 208 1.11 mrg #endif 209 1.11 mrg // The user-supplied clock may not tick at the same rate as 210 1.11 mrg // steady_clock, so we must loop in order to guarantee that 211 1.11 mrg // the timeout has expired before returning false. 212 1.11 mrg auto __now = _Clock::now(); 213 1.11 mrg do { 214 1.11 mrg auto __rtime = __atime - __now; 215 1.11 mrg if (_M_try_lock_for(__rtime)) 216 1.11 mrg return true; 217 1.11 mrg __now = _Clock::now(); 218 1.11 mrg } while (__atime > __now); 219 1.11 mrg return false; 220 1.5 mrg } 221 1.5 mrg }; 222 1.12 mrg /// @endcond 223 1.5 mrg 224 1.12 mrg /** The standard timed mutex type. 225 1.12 mrg * 226 1.12 mrg * A non-recursive mutex that supports a timeout when trying to acquire the 227 1.12 mrg * lock. 228 1.12 mrg * 229 1.12 mrg * @headerfile mutex 230 1.12 mrg * @since C++11 231 1.12 mrg */ 232 1.5 mrg class timed_mutex 233 1.5 mrg : private __mutex_base, public __timed_mutex_impl<timed_mutex> 234 1.1 mrg { 235 1.1 mrg public: 236 1.1 mrg typedef __native_type* native_handle_type; 237 1.1 mrg 238 1.3 mrg timed_mutex() = default; 239 1.3 mrg ~timed_mutex() = default; 240 1.1 mrg 241 1.1 mrg timed_mutex(const timed_mutex&) = delete; 242 1.1 mrg timed_mutex& operator=(const timed_mutex&) = delete; 243 1.1 mrg 244 1.1 mrg void 245 1.1 mrg lock() 246 1.1 mrg { 247 1.1 mrg int __e = __gthread_mutex_lock(&_M_mutex); 248 1.1 mrg 249 1.1 mrg // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 250 1.1 mrg if (__e) 251 1.1 mrg __throw_system_error(__e); 252 1.1 mrg } 253 1.1 mrg 254 1.1 mrg bool 255 1.3 mrg try_lock() noexcept 256 1.1 mrg { 257 1.1 mrg // XXX EINVAL, EAGAIN, EBUSY 258 1.1 mrg return !__gthread_mutex_trylock(&_M_mutex); 259 1.1 mrg } 260 1.1 mrg 261 1.1 mrg template <class _Rep, class _Period> 262 1.1 mrg bool 263 1.1 mrg try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 264 1.3 mrg { return _M_try_lock_for(__rtime); } 265 1.1 mrg 266 1.1 mrg template <class _Clock, class _Duration> 267 1.1 mrg bool 268 1.1 mrg try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 269 1.3 mrg { return _M_try_lock_until(__atime); } 270 1.1 mrg 271 1.1 mrg void 272 1.1 mrg unlock() 273 1.1 mrg { 274 1.1 mrg // XXX EINVAL, EAGAIN, EBUSY 275 1.1 mrg __gthread_mutex_unlock(&_M_mutex); 276 1.1 mrg } 277 1.1 mrg 278 1.1 mrg native_handle_type 279 1.8 mrg native_handle() noexcept 280 1.1 mrg { return &_M_mutex; } 281 1.6 mrg 282 1.6 mrg private: 283 1.6 mrg friend class __timed_mutex_impl<timed_mutex>; 284 1.6 mrg 285 1.6 mrg bool 286 1.6 mrg _M_timedlock(const __gthread_time_t& __ts) 287 1.6 mrg { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); } 288 1.11 mrg 289 1.11 mrg #if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK 290 1.11 mrg bool 291 1.12 mrg _M_clocklock(clockid_t __clockid, const __gthread_time_t& __ts) 292 1.12 mrg { return !pthread_mutex_clocklock(&_M_mutex, __clockid, &__ts); } 293 1.11 mrg #endif 294 1.1 mrg }; 295 1.1 mrg 296 1.12 mrg /** The standard recursive timed mutex type. 297 1.12 mrg * 298 1.12 mrg * A recursive mutex that supports a timeout when trying to acquire the 299 1.12 mrg * lock. A recursive mutex can be locked more than once by the same thread. 300 1.12 mrg * Other threads cannot lock the mutex until the owning thread unlocks it 301 1.12 mrg * as many times as it was locked. 302 1.12 mrg * 303 1.12 mrg * @headerfile mutex 304 1.12 mrg * @since C++11 305 1.12 mrg */ 306 1.5 mrg class recursive_timed_mutex 307 1.5 mrg : private __recursive_mutex_base, 308 1.5 mrg public __timed_mutex_impl<recursive_timed_mutex> 309 1.1 mrg { 310 1.1 mrg public: 311 1.1 mrg typedef __native_type* native_handle_type; 312 1.1 mrg 313 1.3 mrg recursive_timed_mutex() = default; 314 1.3 mrg ~recursive_timed_mutex() = default; 315 1.1 mrg 316 1.1 mrg recursive_timed_mutex(const recursive_timed_mutex&) = delete; 317 1.1 mrg recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 318 1.1 mrg 319 1.1 mrg void 320 1.1 mrg lock() 321 1.1 mrg { 322 1.1 mrg int __e = __gthread_recursive_mutex_lock(&_M_mutex); 323 1.1 mrg 324 1.1 mrg // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 325 1.1 mrg if (__e) 326 1.1 mrg __throw_system_error(__e); 327 1.1 mrg } 328 1.1 mrg 329 1.1 mrg bool 330 1.3 mrg try_lock() noexcept 331 1.1 mrg { 332 1.1 mrg // XXX EINVAL, EAGAIN, EBUSY 333 1.1 mrg return !__gthread_recursive_mutex_trylock(&_M_mutex); 334 1.1 mrg } 335 1.1 mrg 336 1.1 mrg template <class _Rep, class _Period> 337 1.1 mrg bool 338 1.1 mrg try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 339 1.3 mrg { return _M_try_lock_for(__rtime); } 340 1.1 mrg 341 1.1 mrg template <class _Clock, class _Duration> 342 1.1 mrg bool 343 1.1 mrg try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 344 1.3 mrg { return _M_try_lock_until(__atime); } 345 1.1 mrg 346 1.1 mrg void 347 1.1 mrg unlock() 348 1.1 mrg { 349 1.1 mrg // XXX EINVAL, EAGAIN, EBUSY 350 1.1 mrg __gthread_recursive_mutex_unlock(&_M_mutex); 351 1.1 mrg } 352 1.1 mrg 353 1.1 mrg native_handle_type 354 1.8 mrg native_handle() noexcept 355 1.1 mrg { return &_M_mutex; } 356 1.6 mrg 357 1.6 mrg private: 358 1.6 mrg friend class __timed_mutex_impl<recursive_timed_mutex>; 359 1.6 mrg 360 1.6 mrg bool 361 1.6 mrg _M_timedlock(const __gthread_time_t& __ts) 362 1.6 mrg { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); } 363 1.11 mrg 364 1.11 mrg #ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK 365 1.11 mrg bool 366 1.12 mrg _M_clocklock(clockid_t __clockid, const __gthread_time_t& __ts) 367 1.12 mrg { return !pthread_mutex_clocklock(&_M_mutex, __clockid, &__ts); } 368 1.11 mrg #endif 369 1.1 mrg }; 370 1.1 mrg 371 1.6 mrg #else // !_GTHREAD_USE_MUTEX_TIMEDLOCK 372 1.1 mrg 373 1.6 mrg /// timed_mutex 374 1.6 mrg class timed_mutex 375 1.6 mrg { 376 1.6 mrg mutex _M_mut; 377 1.6 mrg condition_variable _M_cv; 378 1.6 mrg bool _M_locked = false; 379 1.1 mrg 380 1.6 mrg public: 381 1.1 mrg 382 1.6 mrg timed_mutex() = default; 383 1.6 mrg ~timed_mutex() { __glibcxx_assert( !_M_locked ); } 384 1.5 mrg 385 1.6 mrg timed_mutex(const timed_mutex&) = delete; 386 1.6 mrg timed_mutex& operator=(const timed_mutex&) = delete; 387 1.5 mrg 388 1.6 mrg void 389 1.6 mrg lock() 390 1.6 mrg { 391 1.6 mrg unique_lock<mutex> __lk(_M_mut); 392 1.6 mrg _M_cv.wait(__lk, [&]{ return !_M_locked; }); 393 1.6 mrg _M_locked = true; 394 1.6 mrg } 395 1.1 mrg 396 1.6 mrg bool 397 1.6 mrg try_lock() 398 1.1 mrg { 399 1.6 mrg lock_guard<mutex> __lk(_M_mut); 400 1.6 mrg if (_M_locked) 401 1.6 mrg return false; 402 1.6 mrg _M_locked = true; 403 1.6 mrg return true; 404 1.6 mrg } 405 1.1 mrg 406 1.6 mrg template<typename _Rep, typename _Period> 407 1.6 mrg bool 408 1.6 mrg try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 409 1.1 mrg { 410 1.6 mrg unique_lock<mutex> __lk(_M_mut); 411 1.6 mrg if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; })) 412 1.6 mrg return false; 413 1.6 mrg _M_locked = true; 414 1.6 mrg return true; 415 1.1 mrg } 416 1.1 mrg 417 1.6 mrg template<typename _Clock, typename _Duration> 418 1.6 mrg bool 419 1.6 mrg try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 420 1.1 mrg { 421 1.6 mrg unique_lock<mutex> __lk(_M_mut); 422 1.6 mrg if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; })) 423 1.6 mrg return false; 424 1.6 mrg _M_locked = true; 425 1.6 mrg return true; 426 1.1 mrg } 427 1.1 mrg 428 1.6 mrg void 429 1.6 mrg unlock() 430 1.6 mrg { 431 1.6 mrg lock_guard<mutex> __lk(_M_mut); 432 1.6 mrg __glibcxx_assert( _M_locked ); 433 1.6 mrg _M_locked = false; 434 1.6 mrg _M_cv.notify_one(); 435 1.6 mrg } 436 1.6 mrg }; 437 1.1 mrg 438 1.6 mrg /// recursive_timed_mutex 439 1.6 mrg class recursive_timed_mutex 440 1.6 mrg { 441 1.6 mrg mutex _M_mut; 442 1.6 mrg condition_variable _M_cv; 443 1.6 mrg thread::id _M_owner; 444 1.6 mrg unsigned _M_count = 0; 445 1.1 mrg 446 1.6 mrg // Predicate type that tests whether the current thread can lock a mutex. 447 1.6 mrg struct _Can_lock 448 1.6 mrg { 449 1.6 mrg // Returns true if the mutex is unlocked or is locked by _M_caller. 450 1.6 mrg bool 451 1.6 mrg operator()() const noexcept 452 1.6 mrg { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; } 453 1.1 mrg 454 1.6 mrg const recursive_timed_mutex* _M_mx; 455 1.6 mrg thread::id _M_caller; 456 1.6 mrg }; 457 1.1 mrg 458 1.6 mrg public: 459 1.1 mrg 460 1.6 mrg recursive_timed_mutex() = default; 461 1.6 mrg ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); } 462 1.1 mrg 463 1.6 mrg recursive_timed_mutex(const recursive_timed_mutex&) = delete; 464 1.6 mrg recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 465 1.1 mrg 466 1.6 mrg void 467 1.6 mrg lock() 468 1.6 mrg { 469 1.6 mrg auto __id = this_thread::get_id(); 470 1.6 mrg _Can_lock __can_lock{this, __id}; 471 1.6 mrg unique_lock<mutex> __lk(_M_mut); 472 1.6 mrg _M_cv.wait(__lk, __can_lock); 473 1.6 mrg if (_M_count == -1u) 474 1.6 mrg __throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3 475 1.6 mrg _M_owner = __id; 476 1.6 mrg ++_M_count; 477 1.6 mrg } 478 1.1 mrg 479 1.6 mrg bool 480 1.6 mrg try_lock() 481 1.6 mrg { 482 1.6 mrg auto __id = this_thread::get_id(); 483 1.6 mrg _Can_lock __can_lock{this, __id}; 484 1.6 mrg lock_guard<mutex> __lk(_M_mut); 485 1.6 mrg if (!__can_lock()) 486 1.6 mrg return false; 487 1.6 mrg if (_M_count == -1u) 488 1.6 mrg return false; 489 1.6 mrg _M_owner = __id; 490 1.6 mrg ++_M_count; 491 1.6 mrg return true; 492 1.6 mrg } 493 1.1 mrg 494 1.6 mrg template<typename _Rep, typename _Period> 495 1.6 mrg bool 496 1.6 mrg try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 497 1.1 mrg { 498 1.6 mrg auto __id = this_thread::get_id(); 499 1.6 mrg _Can_lock __can_lock{this, __id}; 500 1.6 mrg unique_lock<mutex> __lk(_M_mut); 501 1.6 mrg if (!_M_cv.wait_for(__lk, __rtime, __can_lock)) 502 1.6 mrg return false; 503 1.6 mrg if (_M_count == -1u) 504 1.6 mrg return false; 505 1.6 mrg _M_owner = __id; 506 1.6 mrg ++_M_count; 507 1.6 mrg return true; 508 1.1 mrg } 509 1.1 mrg 510 1.6 mrg template<typename _Clock, typename _Duration> 511 1.1 mrg bool 512 1.6 mrg try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 513 1.1 mrg { 514 1.6 mrg auto __id = this_thread::get_id(); 515 1.6 mrg _Can_lock __can_lock{this, __id}; 516 1.6 mrg unique_lock<mutex> __lk(_M_mut); 517 1.6 mrg if (!_M_cv.wait_until(__lk, __atime, __can_lock)) 518 1.6 mrg return false; 519 1.6 mrg if (_M_count == -1u) 520 1.6 mrg return false; 521 1.6 mrg _M_owner = __id; 522 1.6 mrg ++_M_count; 523 1.6 mrg return true; 524 1.1 mrg } 525 1.1 mrg 526 1.6 mrg void 527 1.6 mrg unlock() 528 1.6 mrg { 529 1.6 mrg lock_guard<mutex> __lk(_M_mut); 530 1.6 mrg __glibcxx_assert( _M_owner == this_thread::get_id() ); 531 1.6 mrg __glibcxx_assert( _M_count > 0 ); 532 1.6 mrg if (--_M_count == 0) 533 1.1 mrg { 534 1.6 mrg _M_owner = {}; 535 1.6 mrg _M_cv.notify_one(); 536 1.1 mrg } 537 1.6 mrg } 538 1.6 mrg }; 539 1.1 mrg 540 1.6 mrg #endif 541 1.6 mrg #endif // _GLIBCXX_HAS_GTHREADS 542 1.1 mrg 543 1.11 mrg /// @cond undocumented 544 1.12 mrg namespace __detail 545 1.12 mrg { 546 1.12 mrg // Lock the last lockable, after all previous ones are locked. 547 1.12 mrg template<typename _Lockable> 548 1.12 mrg inline int 549 1.12 mrg __try_lock_impl(_Lockable& __l) 550 1.12 mrg { 551 1.12 mrg if (unique_lock<_Lockable> __lock{__l, try_to_lock}) 552 1.12 mrg { 553 1.12 mrg __lock.release(); 554 1.12 mrg return -1; 555 1.12 mrg } 556 1.12 mrg else 557 1.12 mrg return 0; 558 1.12 mrg } 559 1.12 mrg 560 1.12 mrg // Lock each lockable in turn. 561 1.12 mrg // Use iteration if all lockables are the same type, recursion otherwise. 562 1.12 mrg template<typename _L0, typename... _Lockables> 563 1.12 mrg inline int 564 1.12 mrg __try_lock_impl(_L0& __l0, _Lockables&... __lockables) 565 1.12 mrg { 566 1.12 mrg #if __cplusplus >= 201703L 567 1.12 mrg if constexpr ((is_same_v<_L0, _Lockables> && ...)) 568 1.12 mrg { 569 1.12 mrg constexpr int _Np = 1 + sizeof...(_Lockables); 570 1.12 mrg unique_lock<_L0> __locks[_Np] = { 571 1.12 mrg {__l0, defer_lock}, {__lockables, defer_lock}... 572 1.12 mrg }; 573 1.12 mrg for (int __i = 0; __i < _Np; ++__i) 574 1.12 mrg { 575 1.12 mrg if (!__locks[__i].try_lock()) 576 1.12 mrg { 577 1.12 mrg const int __failed = __i; 578 1.12 mrg while (__i--) 579 1.12 mrg __locks[__i].unlock(); 580 1.12 mrg return __failed; 581 1.12 mrg } 582 1.12 mrg } 583 1.12 mrg for (auto& __l : __locks) 584 1.12 mrg __l.release(); 585 1.12 mrg return -1; 586 1.12 mrg } 587 1.12 mrg else 588 1.12 mrg #endif 589 1.12 mrg if (unique_lock<_L0> __lock{__l0, try_to_lock}) 590 1.12 mrg { 591 1.12 mrg int __idx = __detail::__try_lock_impl(__lockables...); 592 1.12 mrg if (__idx == -1) 593 1.12 mrg { 594 1.12 mrg __lock.release(); 595 1.12 mrg return -1; 596 1.12 mrg } 597 1.12 mrg return __idx + 1; 598 1.12 mrg } 599 1.12 mrg else 600 1.12 mrg return 0; 601 1.12 mrg } 602 1.1 mrg 603 1.12 mrg } // namespace __detail 604 1.11 mrg /// @endcond 605 1.1 mrg 606 1.1 mrg /** @brief Generic try_lock. 607 1.9 mrg * @param __l1 Meets Lockable requirements (try_lock() may throw). 608 1.9 mrg * @param __l2 Meets Lockable requirements (try_lock() may throw). 609 1.9 mrg * @param __l3 Meets Lockable requirements (try_lock() may throw). 610 1.1 mrg * @return Returns -1 if all try_lock() calls return true. Otherwise returns 611 1.1 mrg * a 0-based index corresponding to the argument that returned false. 612 1.1 mrg * @post Either all arguments are locked, or none will be. 613 1.1 mrg * 614 1.1 mrg * Sequentially calls try_lock() on each argument. 615 1.1 mrg */ 616 1.12 mrg template<typename _L1, typename _L2, typename... _L3> 617 1.12 mrg inline int 618 1.12 mrg try_lock(_L1& __l1, _L2& __l2, _L3&... __l3) 619 1.12 mrg { 620 1.12 mrg return __detail::__try_lock_impl(__l1, __l2, __l3...); 621 1.1 mrg } 622 1.1 mrg 623 1.12 mrg /// @cond undocumented 624 1.12 mrg namespace __detail 625 1.12 mrg { 626 1.12 mrg // This function can recurse up to N levels deep, for N = 1+sizeof...(L1). 627 1.12 mrg // On each recursion the lockables are rotated left one position, 628 1.12 mrg // e.g. depth 0: l0, l1, l2; depth 1: l1, l2, l0; depth 2: l2, l0, l1. 629 1.12 mrg // When a call to l_i.try_lock() fails it recurses/returns to depth=i 630 1.12 mrg // so that l_i is the first argument, and then blocks until l_i is locked. 631 1.12 mrg template<typename _L0, typename... _L1> 632 1.12 mrg void 633 1.12 mrg __lock_impl(int& __i, int __depth, _L0& __l0, _L1&... __l1) 634 1.12 mrg { 635 1.12 mrg while (__i >= __depth) 636 1.12 mrg { 637 1.12 mrg if (__i == __depth) 638 1.12 mrg { 639 1.12 mrg int __failed = 1; // index that couldn't be locked 640 1.12 mrg { 641 1.12 mrg unique_lock<_L0> __first(__l0); 642 1.12 mrg __failed += __detail::__try_lock_impl(__l1...); 643 1.12 mrg if (!__failed) 644 1.12 mrg { 645 1.12 mrg __i = -1; // finished 646 1.12 mrg __first.release(); 647 1.12 mrg return; 648 1.12 mrg } 649 1.12 mrg } 650 1.12 mrg #if defined _GLIBCXX_HAS_GTHREADS && defined _GLIBCXX_USE_SCHED_YIELD 651 1.12 mrg __gthread_yield(); 652 1.12 mrg #endif 653 1.12 mrg constexpr auto __n = 1 + sizeof...(_L1); 654 1.12 mrg __i = (__depth + __failed) % __n; 655 1.12 mrg } 656 1.12 mrg else // rotate left until l_i is first. 657 1.12 mrg __detail::__lock_impl(__i, __depth + 1, __l1..., __l0); 658 1.12 mrg } 659 1.12 mrg } 660 1.12 mrg 661 1.12 mrg } // namespace __detail 662 1.12 mrg /// @endcond 663 1.12 mrg 664 1.3 mrg /** @brief Generic lock. 665 1.9 mrg * @param __l1 Meets Lockable requirements (try_lock() may throw). 666 1.9 mrg * @param __l2 Meets Lockable requirements (try_lock() may throw). 667 1.9 mrg * @param __l3 Meets Lockable requirements (try_lock() may throw). 668 1.3 mrg * @throw An exception thrown by an argument's lock() or try_lock() member. 669 1.3 mrg * @post All arguments are locked. 670 1.3 mrg * 671 1.3 mrg * All arguments are locked via a sequence of calls to lock(), try_lock() 672 1.12 mrg * and unlock(). If this function exits via an exception any locks that 673 1.12 mrg * were obtained will be released. 674 1.3 mrg */ 675 1.5 mrg template<typename _L1, typename _L2, typename... _L3> 676 1.1 mrg void 677 1.3 mrg lock(_L1& __l1, _L2& __l2, _L3&... __l3) 678 1.3 mrg { 679 1.12 mrg #if __cplusplus >= 201703L 680 1.12 mrg if constexpr (is_same_v<_L1, _L2> && (is_same_v<_L1, _L3> && ...)) 681 1.12 mrg { 682 1.12 mrg constexpr int _Np = 2 + sizeof...(_L3); 683 1.12 mrg unique_lock<_L1> __locks[] = { 684 1.12 mrg {__l1, defer_lock}, {__l2, defer_lock}, {__l3, defer_lock}... 685 1.12 mrg }; 686 1.12 mrg int __first = 0; 687 1.12 mrg do { 688 1.12 mrg __locks[__first].lock(); 689 1.12 mrg for (int __j = 1; __j < _Np; ++__j) 690 1.12 mrg { 691 1.12 mrg const int __idx = (__first + __j) % _Np; 692 1.12 mrg if (!__locks[__idx].try_lock()) 693 1.12 mrg { 694 1.12 mrg for (int __k = __j; __k != 0; --__k) 695 1.12 mrg __locks[(__first + __k - 1) % _Np].unlock(); 696 1.12 mrg __first = __idx; 697 1.12 mrg break; 698 1.12 mrg } 699 1.12 mrg } 700 1.12 mrg } while (!__locks[__first].owns_lock()); 701 1.12 mrg 702 1.12 mrg for (auto& __l : __locks) 703 1.12 mrg __l.release(); 704 1.12 mrg } 705 1.12 mrg else 706 1.12 mrg #endif 707 1.12 mrg { 708 1.12 mrg int __i = 0; 709 1.12 mrg __detail::__lock_impl(__i, 0, __l1, __l2, __l3...); 710 1.12 mrg } 711 1.3 mrg } 712 1.1 mrg 713 1.8 mrg #if __cplusplus >= 201703L 714 1.12 mrg #define __cpp_lib_scoped_lock 201703L 715 1.8 mrg /** @brief A scoped lock type for multiple lockable objects. 716 1.8 mrg * 717 1.8 mrg * A scoped_lock controls mutex ownership within a scope, releasing 718 1.8 mrg * ownership in the destructor. 719 1.12 mrg * 720 1.12 mrg * @headerfile mutex 721 1.12 mrg * @since C++17 722 1.8 mrg */ 723 1.8 mrg template<typename... _MutexTypes> 724 1.8 mrg class scoped_lock 725 1.8 mrg { 726 1.8 mrg public: 727 1.8 mrg explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...)) 728 1.8 mrg { std::lock(__m...); } 729 1.8 mrg 730 1.8 mrg explicit scoped_lock(adopt_lock_t, _MutexTypes&... __m) noexcept 731 1.8 mrg : _M_devices(std::tie(__m...)) 732 1.8 mrg { } // calling thread owns mutex 733 1.8 mrg 734 1.8 mrg ~scoped_lock() 735 1.11 mrg { std::apply([](auto&... __m) { (__m.unlock(), ...); }, _M_devices); } 736 1.8 mrg 737 1.8 mrg scoped_lock(const scoped_lock&) = delete; 738 1.8 mrg scoped_lock& operator=(const scoped_lock&) = delete; 739 1.8 mrg 740 1.8 mrg private: 741 1.8 mrg tuple<_MutexTypes&...> _M_devices; 742 1.8 mrg }; 743 1.8 mrg 744 1.8 mrg template<> 745 1.8 mrg class scoped_lock<> 746 1.8 mrg { 747 1.8 mrg public: 748 1.8 mrg explicit scoped_lock() = default; 749 1.8 mrg explicit scoped_lock(adopt_lock_t) noexcept { } 750 1.8 mrg ~scoped_lock() = default; 751 1.8 mrg 752 1.8 mrg scoped_lock(const scoped_lock&) = delete; 753 1.8 mrg scoped_lock& operator=(const scoped_lock&) = delete; 754 1.8 mrg }; 755 1.8 mrg 756 1.8 mrg template<typename _Mutex> 757 1.8 mrg class scoped_lock<_Mutex> 758 1.8 mrg { 759 1.8 mrg public: 760 1.8 mrg using mutex_type = _Mutex; 761 1.8 mrg 762 1.8 mrg explicit scoped_lock(mutex_type& __m) : _M_device(__m) 763 1.8 mrg { _M_device.lock(); } 764 1.8 mrg 765 1.8 mrg explicit scoped_lock(adopt_lock_t, mutex_type& __m) noexcept 766 1.8 mrg : _M_device(__m) 767 1.8 mrg { } // calling thread owns mutex 768 1.8 mrg 769 1.8 mrg ~scoped_lock() 770 1.8 mrg { _M_device.unlock(); } 771 1.8 mrg 772 1.8 mrg scoped_lock(const scoped_lock&) = delete; 773 1.8 mrg scoped_lock& operator=(const scoped_lock&) = delete; 774 1.8 mrg 775 1.8 mrg private: 776 1.8 mrg mutex_type& _M_device; 777 1.8 mrg }; 778 1.8 mrg #endif // C++17 779 1.8 mrg 780 1.3 mrg #ifdef _GLIBCXX_HAS_GTHREADS 781 1.11 mrg /// Flag type used by std::call_once 782 1.1 mrg struct once_flag 783 1.1 mrg { 784 1.3 mrg constexpr once_flag() noexcept = default; 785 1.1 mrg 786 1.3 mrg /// Deleted copy constructor 787 1.1 mrg once_flag(const once_flag&) = delete; 788 1.3 mrg /// Deleted assignment operator 789 1.1 mrg once_flag& operator=(const once_flag&) = delete; 790 1.1 mrg 791 1.12 mrg private: 792 1.12 mrg // For gthreads targets a pthread_once_t is used with pthread_once, but 793 1.12 mrg // for most targets this doesn't work correctly for exceptional executions. 794 1.12 mrg __gthread_once_t _M_once = __GTHREAD_ONCE_INIT; 795 1.12 mrg 796 1.12 mrg struct _Prepare_execution; 797 1.12 mrg 798 1.1 mrg template<typename _Callable, typename... _Args> 799 1.1 mrg friend void 800 1.3 mrg call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); 801 1.1 mrg }; 802 1.1 mrg 803 1.11 mrg /// @cond undocumented 804 1.12 mrg # ifdef _GLIBCXX_HAVE_TLS 805 1.12 mrg // If TLS is available use thread-local state for the type-erased callable 806 1.12 mrg // that is being run by std::call_once in the current thread. 807 1.1 mrg extern __thread void* __once_callable; 808 1.1 mrg extern __thread void (*__once_call)(); 809 1.12 mrg 810 1.12 mrg // RAII type to set up state for pthread_once call. 811 1.12 mrg struct once_flag::_Prepare_execution 812 1.12 mrg { 813 1.12 mrg template<typename _Callable> 814 1.12 mrg explicit 815 1.12 mrg _Prepare_execution(_Callable& __c) 816 1.12 mrg { 817 1.12 mrg // Store address in thread-local pointer: 818 1.12 mrg __once_callable = std::__addressof(__c); 819 1.12 mrg // Trampoline function to invoke the closure via thread-local pointer: 820 1.12 mrg __once_call = [] { (*static_cast<_Callable*>(__once_callable))(); }; 821 1.12 mrg } 822 1.12 mrg 823 1.12 mrg ~_Prepare_execution() 824 1.12 mrg { 825 1.12 mrg // PR libstdc++/82481 826 1.12 mrg __once_callable = nullptr; 827 1.12 mrg __once_call = nullptr; 828 1.12 mrg } 829 1.12 mrg 830 1.12 mrg _Prepare_execution(const _Prepare_execution&) = delete; 831 1.12 mrg _Prepare_execution& operator=(const _Prepare_execution&) = delete; 832 1.12 mrg }; 833 1.12 mrg 834 1.12 mrg # else 835 1.12 mrg // Without TLS use a global std::mutex and store the callable in a 836 1.12 mrg // global std::function. 837 1.1 mrg extern function<void()> __once_functor; 838 1.1 mrg 839 1.1 mrg extern void 840 1.1 mrg __set_once_functor_lock_ptr(unique_lock<mutex>*); 841 1.1 mrg 842 1.1 mrg extern mutex& 843 1.1 mrg __get_once_mutex(); 844 1.1 mrg 845 1.12 mrg // RAII type to set up state for pthread_once call. 846 1.12 mrg struct once_flag::_Prepare_execution 847 1.12 mrg { 848 1.12 mrg template<typename _Callable> 849 1.12 mrg explicit 850 1.12 mrg _Prepare_execution(_Callable& __c) 851 1.12 mrg { 852 1.12 mrg // Store the callable in the global std::function 853 1.12 mrg __once_functor = __c; 854 1.12 mrg __set_once_functor_lock_ptr(&_M_functor_lock); 855 1.12 mrg } 856 1.12 mrg 857 1.12 mrg ~_Prepare_execution() 858 1.12 mrg { 859 1.12 mrg if (_M_functor_lock) 860 1.12 mrg __set_once_functor_lock_ptr(nullptr); 861 1.12 mrg } 862 1.12 mrg 863 1.12 mrg private: 864 1.12 mrg // XXX This deadlocks if used recursively (PR 97949) 865 1.12 mrg unique_lock<mutex> _M_functor_lock{__get_once_mutex()}; 866 1.12 mrg 867 1.12 mrg _Prepare_execution(const _Prepare_execution&) = delete; 868 1.12 mrg _Prepare_execution& operator=(const _Prepare_execution&) = delete; 869 1.12 mrg }; 870 1.12 mrg # endif 871 1.12 mrg /// @endcond 872 1.12 mrg 873 1.12 mrg // This function is passed to pthread_once by std::call_once. 874 1.12 mrg // It runs __once_call() or __once_functor(). 875 1.3 mrg extern "C" void __once_proxy(void); 876 1.1 mrg 877 1.11 mrg /// Invoke a callable and synchronize with other calls using the same flag 878 1.1 mrg template<typename _Callable, typename... _Args> 879 1.1 mrg void 880 1.3 mrg call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) 881 1.1 mrg { 882 1.12 mrg // Closure type that runs the function 883 1.6 mrg auto __callable = [&] { 884 1.6 mrg std::__invoke(std::forward<_Callable>(__f), 885 1.6 mrg std::forward<_Args>(__args)...); 886 1.6 mrg }; 887 1.1 mrg 888 1.12 mrg once_flag::_Prepare_execution __exec(__callable); 889 1.12 mrg 890 1.12 mrg // XXX pthread_once does not reset the flag if an exception is thrown. 891 1.12 mrg if (int __e = __gthread_once(&__once._M_once, &__once_proxy)) 892 1.12 mrg __throw_system_error(__e); 893 1.12 mrg } 894 1.12 mrg 895 1.12 mrg #else // _GLIBCXX_HAS_GTHREADS 896 1.12 mrg 897 1.12 mrg /// Flag type used by std::call_once 898 1.12 mrg struct once_flag 899 1.12 mrg { 900 1.12 mrg constexpr once_flag() noexcept = default; 901 1.12 mrg 902 1.12 mrg /// Deleted copy constructor 903 1.12 mrg once_flag(const once_flag&) = delete; 904 1.12 mrg /// Deleted assignment operator 905 1.12 mrg once_flag& operator=(const once_flag&) = delete; 906 1.12 mrg 907 1.12 mrg private: 908 1.12 mrg // There are two different std::once_flag interfaces, abstracting four 909 1.12 mrg // different implementations. 910 1.12 mrg // The single-threaded interface uses the _M_activate() and _M_finish(bool) 911 1.12 mrg // functions, which start and finish an active execution respectively. 912 1.12 mrg // See [thread.once.callonce] in C++11 for the definition of 913 1.12 mrg // active/passive/returning/exceptional executions. 914 1.12 mrg enum _Bits : int { _Init = 0, _Active = 1, _Done = 2 }; 915 1.12 mrg 916 1.12 mrg int _M_once = _Bits::_Init; 917 1.12 mrg 918 1.12 mrg // Check to see if all executions will be passive now. 919 1.12 mrg bool 920 1.12 mrg _M_passive() const noexcept; 921 1.12 mrg 922 1.12 mrg // Attempts to begin an active execution. 923 1.12 mrg bool _M_activate(); 924 1.12 mrg 925 1.12 mrg // Must be called to complete an active execution. 926 1.12 mrg // The argument is true if the active execution was a returning execution, 927 1.12 mrg // false if it was an exceptional execution. 928 1.12 mrg void _M_finish(bool __returning) noexcept; 929 1.12 mrg 930 1.12 mrg // RAII helper to call _M_finish. 931 1.12 mrg struct _Active_execution 932 1.12 mrg { 933 1.12 mrg explicit _Active_execution(once_flag& __flag) : _M_flag(__flag) { } 934 1.12 mrg 935 1.12 mrg ~_Active_execution() { _M_flag._M_finish(_M_returning); } 936 1.12 mrg 937 1.12 mrg _Active_execution(const _Active_execution&) = delete; 938 1.12 mrg _Active_execution& operator=(const _Active_execution&) = delete; 939 1.12 mrg 940 1.12 mrg once_flag& _M_flag; 941 1.12 mrg bool _M_returning = false; 942 1.12 mrg }; 943 1.12 mrg 944 1.12 mrg template<typename _Callable, typename... _Args> 945 1.12 mrg friend void 946 1.12 mrg call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); 947 1.12 mrg }; 948 1.12 mrg 949 1.12 mrg // Inline definitions of std::once_flag members for single-threaded targets. 950 1.12 mrg 951 1.12 mrg inline bool 952 1.12 mrg once_flag::_M_passive() const noexcept 953 1.12 mrg { return _M_once == _Bits::_Done; } 954 1.12 mrg 955 1.12 mrg inline bool 956 1.12 mrg once_flag::_M_activate() 957 1.12 mrg { 958 1.12 mrg if (_M_once == _Bits::_Init) [[__likely__]] 959 1.12 mrg { 960 1.12 mrg _M_once = _Bits::_Active; 961 1.12 mrg return true; 962 1.12 mrg } 963 1.12 mrg else if (_M_passive()) // Caller should have checked this already. 964 1.12 mrg return false; 965 1.12 mrg else 966 1.12 mrg __throw_system_error(EDEADLK); 967 1.12 mrg } 968 1.12 mrg 969 1.12 mrg inline void 970 1.12 mrg once_flag::_M_finish(bool __returning) noexcept 971 1.12 mrg { _M_once = __returning ? _Bits::_Done : _Bits::_Init; } 972 1.12 mrg 973 1.12 mrg /// Invoke a callable and synchronize with other calls using the same flag 974 1.12 mrg template<typename _Callable, typename... _Args> 975 1.12 mrg inline void 976 1.12 mrg call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) 977 1.12 mrg { 978 1.12 mrg if (__once._M_passive()) 979 1.12 mrg return; 980 1.12 mrg else if (__once._M_activate()) 981 1.12 mrg { 982 1.12 mrg once_flag::_Active_execution __exec(__once); 983 1.1 mrg 984 1.12 mrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 985 1.12 mrg // 2442. call_once() shouldn't DECAY_COPY() 986 1.12 mrg std::__invoke(std::forward<_Callable>(__f), 987 1.12 mrg std::forward<_Args>(__args)...); 988 1.1 mrg 989 1.12 mrg // __f(__args...) did not throw 990 1.12 mrg __exec._M_returning = true; 991 1.12 mrg } 992 1.1 mrg } 993 1.3 mrg #endif // _GLIBCXX_HAS_GTHREADS 994 1.1 mrg 995 1.11 mrg /// @} group mutexes 996 1.3 mrg _GLIBCXX_END_NAMESPACE_VERSION 997 1.3 mrg } // namespace 998 1.1 mrg 999 1.3 mrg #endif // C++11 1000 1.1 mrg 1001 1.1 mrg #endif // _GLIBCXX_MUTEX 1002