1e4b17023SJohn Marino// <mutex> -*- C++ -*- 2e4b17023SJohn Marino 3*5ce9237cSJohn Marino// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013 4e4b17023SJohn Marino// Free Software Foundation, Inc. 5e4b17023SJohn Marino// 6e4b17023SJohn Marino// This file is part of the GNU ISO C++ Library. This library is free 7e4b17023SJohn Marino// software; you can redistribute it and/or modify it under the 8e4b17023SJohn Marino// terms of the GNU General Public License as published by the 9e4b17023SJohn Marino// Free Software Foundation; either version 3, or (at your option) 10e4b17023SJohn Marino// any later version. 11e4b17023SJohn Marino 12e4b17023SJohn Marino// This library is distributed in the hope that it will be useful, 13e4b17023SJohn Marino// but WITHOUT ANY WARRANTY; without even the implied warranty of 14e4b17023SJohn Marino// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15e4b17023SJohn Marino// GNU General Public License for more details. 16e4b17023SJohn Marino 17e4b17023SJohn Marino// Under Section 7 of GPL version 3, you are granted additional 18e4b17023SJohn Marino// permissions described in the GCC Runtime Library Exception, version 19e4b17023SJohn Marino// 3.1, as published by the Free Software Foundation. 20e4b17023SJohn Marino 21e4b17023SJohn Marino// You should have received a copy of the GNU General Public License and 22e4b17023SJohn Marino// a copy of the GCC Runtime Library Exception along with this program; 23e4b17023SJohn Marino// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24e4b17023SJohn Marino// <http://www.gnu.org/licenses/>. 25e4b17023SJohn Marino 26e4b17023SJohn Marino/** @file include/mutex 27e4b17023SJohn Marino * This is a Standard C++ Library header. 28e4b17023SJohn Marino */ 29e4b17023SJohn Marino 30e4b17023SJohn Marino#ifndef _GLIBCXX_MUTEX 31e4b17023SJohn Marino#define _GLIBCXX_MUTEX 1 32e4b17023SJohn Marino 33e4b17023SJohn Marino#pragma GCC system_header 34e4b17023SJohn Marino 35e4b17023SJohn Marino#ifndef __GXX_EXPERIMENTAL_CXX0X__ 36e4b17023SJohn Marino# include <bits/c++0x_warning.h> 37e4b17023SJohn Marino#else 38e4b17023SJohn Marino 39e4b17023SJohn Marino#include <tuple> 40e4b17023SJohn Marino#include <chrono> 41e4b17023SJohn Marino#include <exception> 42e4b17023SJohn Marino#include <type_traits> 43e4b17023SJohn Marino#include <functional> 44e4b17023SJohn Marino#include <system_error> 45e4b17023SJohn Marino#include <bits/functexcept.h> 46e4b17023SJohn Marino#include <bits/gthr.h> 47e4b17023SJohn Marino#include <bits/move.h> // for std::swap 48e4b17023SJohn Marino 49*5ce9237cSJohn Marino#ifdef _GLIBCXX_USE_C99_STDINT_TR1 50e4b17023SJohn Marino 51e4b17023SJohn Marinonamespace std _GLIBCXX_VISIBILITY(default) 52e4b17023SJohn Marino{ 53e4b17023SJohn Marino_GLIBCXX_BEGIN_NAMESPACE_VERSION 54e4b17023SJohn Marino 55*5ce9237cSJohn Marino#ifdef _GLIBCXX_HAS_GTHREADS 56e4b17023SJohn Marino // Common base class for std::mutex and std::timed_mutex 57e4b17023SJohn Marino class __mutex_base 58e4b17023SJohn Marino { 59e4b17023SJohn Marino protected: 60e4b17023SJohn Marino typedef __gthread_mutex_t __native_type; 61e4b17023SJohn Marino 62e4b17023SJohn Marino#ifdef __GTHREAD_MUTEX_INIT 63e4b17023SJohn Marino __native_type _M_mutex = __GTHREAD_MUTEX_INIT; 64e4b17023SJohn Marino 65e4b17023SJohn Marino constexpr __mutex_base() noexcept = default; 66e4b17023SJohn Marino#else 67e4b17023SJohn Marino __native_type _M_mutex; 68e4b17023SJohn Marino 69e4b17023SJohn Marino __mutex_base() noexcept 70e4b17023SJohn Marino { 71e4b17023SJohn Marino // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 72e4b17023SJohn Marino __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 73e4b17023SJohn Marino } 74e4b17023SJohn Marino 75e4b17023SJohn Marino ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); } 76e4b17023SJohn Marino#endif 77e4b17023SJohn Marino 78e4b17023SJohn Marino __mutex_base(const __mutex_base&) = delete; 79e4b17023SJohn Marino __mutex_base& operator=(const __mutex_base&) = delete; 80e4b17023SJohn Marino }; 81e4b17023SJohn Marino 82e4b17023SJohn Marino // Common base class for std::recursive_mutex and std::timed_recursive_mutex 83e4b17023SJohn Marino class __recursive_mutex_base 84e4b17023SJohn Marino { 85e4b17023SJohn Marino protected: 86e4b17023SJohn Marino typedef __gthread_recursive_mutex_t __native_type; 87e4b17023SJohn Marino 88e4b17023SJohn Marino __recursive_mutex_base(const __recursive_mutex_base&) = delete; 89e4b17023SJohn Marino __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete; 90e4b17023SJohn Marino 91e4b17023SJohn Marino#ifdef __GTHREAD_RECURSIVE_MUTEX_INIT 92e4b17023SJohn Marino __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 93e4b17023SJohn Marino 94e4b17023SJohn Marino __recursive_mutex_base() = default; 95e4b17023SJohn Marino#else 96e4b17023SJohn Marino __native_type _M_mutex; 97e4b17023SJohn Marino 98e4b17023SJohn Marino __recursive_mutex_base() 99e4b17023SJohn Marino { 100e4b17023SJohn Marino // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 101e4b17023SJohn Marino __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 102e4b17023SJohn Marino } 103e4b17023SJohn Marino 104e4b17023SJohn Marino ~__recursive_mutex_base() 105e4b17023SJohn Marino { _S_destroy(&_M_mutex); } 106e4b17023SJohn Marino 107e4b17023SJohn Marino private: 108e4b17023SJohn Marino // FIXME: gthreads doesn't define __gthread_recursive_mutex_destroy 109e4b17023SJohn Marino // so we need to obtain a __gthread_mutex_t to destroy 110e4b17023SJohn Marino 111e4b17023SJohn Marino // matches when there's only one mutex type 112e4b17023SJohn Marino template<typename _Rm> 113e4b17023SJohn Marino static 114e4b17023SJohn Marino typename enable_if<is_same<_Rm, __gthread_mutex_t>::value, void>::type 115e4b17023SJohn Marino _S_destroy(_Rm* __mx) 116e4b17023SJohn Marino { __gthread_mutex_destroy(__mx); } 117e4b17023SJohn Marino 118e4b17023SJohn Marino // matches a recursive mutex with a member 'actual' 119e4b17023SJohn Marino template<typename _Rm> 120e4b17023SJohn Marino static typename enable_if<(bool)sizeof(&_Rm::actual), void>::type 121e4b17023SJohn Marino _S_destroy(_Rm* __mx) 122e4b17023SJohn Marino { __gthread_mutex_destroy(&__mx->actual); } 123e4b17023SJohn Marino 124e4b17023SJohn Marino // matches a gthr-win32.h recursive mutex 125e4b17023SJohn Marino template<typename _Rm> 126e4b17023SJohn Marino static typename enable_if<(bool)sizeof(&_Rm::sema), void>::type 127e4b17023SJohn Marino _S_destroy(_Rm* __mx) 128e4b17023SJohn Marino { 129e4b17023SJohn Marino __gthread_mutex_t __tmp; 130e4b17023SJohn Marino _S_destroy_win32(&__tmp, __mx); 131e4b17023SJohn Marino } 132e4b17023SJohn Marino 133e4b17023SJohn Marino template<typename _Mx, typename _Rm> 134e4b17023SJohn Marino static void 135e4b17023SJohn Marino _S_destroy_win32(_Mx* __mx, _Rm const* __rmx) 136e4b17023SJohn Marino { 137e4b17023SJohn Marino __mx->counter = __rmx->counter; 138e4b17023SJohn Marino __mx->sema = __rmx->sema; 139e4b17023SJohn Marino __gthread_mutex_destroy(__mx); 140e4b17023SJohn Marino } 141e4b17023SJohn Marino#endif 142e4b17023SJohn Marino }; 143e4b17023SJohn Marino 144e4b17023SJohn Marino /** 145e4b17023SJohn Marino * @defgroup mutexes Mutexes 146e4b17023SJohn Marino * @ingroup concurrency 147e4b17023SJohn Marino * 148e4b17023SJohn Marino * Classes for mutex support. 149e4b17023SJohn Marino * @{ 150e4b17023SJohn Marino */ 151e4b17023SJohn Marino 152e4b17023SJohn Marino /// mutex 153e4b17023SJohn Marino class mutex : private __mutex_base 154e4b17023SJohn Marino { 155e4b17023SJohn Marino public: 156e4b17023SJohn Marino typedef __native_type* native_handle_type; 157e4b17023SJohn Marino 158e4b17023SJohn Marino#ifdef __GTHREAD_MUTEX_INIT 159e4b17023SJohn Marino constexpr 160e4b17023SJohn Marino#endif 161e4b17023SJohn Marino mutex() noexcept = default; 162e4b17023SJohn Marino ~mutex() = default; 163e4b17023SJohn Marino 164e4b17023SJohn Marino mutex(const mutex&) = delete; 165e4b17023SJohn Marino mutex& operator=(const mutex&) = delete; 166e4b17023SJohn Marino 167e4b17023SJohn Marino void 168e4b17023SJohn Marino lock() 169e4b17023SJohn Marino { 170e4b17023SJohn Marino int __e = __gthread_mutex_lock(&_M_mutex); 171e4b17023SJohn Marino 172e4b17023SJohn Marino // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 173e4b17023SJohn Marino if (__e) 174e4b17023SJohn Marino __throw_system_error(__e); 175e4b17023SJohn Marino } 176e4b17023SJohn Marino 177e4b17023SJohn Marino bool 178e4b17023SJohn Marino try_lock() noexcept 179e4b17023SJohn Marino { 180e4b17023SJohn Marino // XXX EINVAL, EAGAIN, EBUSY 181e4b17023SJohn Marino return !__gthread_mutex_trylock(&_M_mutex); 182e4b17023SJohn Marino } 183e4b17023SJohn Marino 184e4b17023SJohn Marino void 185e4b17023SJohn Marino unlock() 186e4b17023SJohn Marino { 187e4b17023SJohn Marino // XXX EINVAL, EAGAIN, EPERM 188e4b17023SJohn Marino __gthread_mutex_unlock(&_M_mutex); 189e4b17023SJohn Marino } 190e4b17023SJohn Marino 191e4b17023SJohn Marino native_handle_type 192e4b17023SJohn Marino native_handle() 193e4b17023SJohn Marino { return &_M_mutex; } 194e4b17023SJohn Marino }; 195e4b17023SJohn Marino 196e4b17023SJohn Marino /// recursive_mutex 197e4b17023SJohn Marino class recursive_mutex : private __recursive_mutex_base 198e4b17023SJohn Marino { 199e4b17023SJohn Marino public: 200e4b17023SJohn Marino typedef __native_type* native_handle_type; 201e4b17023SJohn Marino 202e4b17023SJohn Marino recursive_mutex() = default; 203e4b17023SJohn Marino ~recursive_mutex() = default; 204e4b17023SJohn Marino 205e4b17023SJohn Marino recursive_mutex(const recursive_mutex&) = delete; 206e4b17023SJohn Marino recursive_mutex& operator=(const recursive_mutex&) = delete; 207e4b17023SJohn Marino 208e4b17023SJohn Marino void 209e4b17023SJohn Marino lock() 210e4b17023SJohn Marino { 211e4b17023SJohn Marino int __e = __gthread_recursive_mutex_lock(&_M_mutex); 212e4b17023SJohn Marino 213e4b17023SJohn Marino // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 214e4b17023SJohn Marino if (__e) 215e4b17023SJohn Marino __throw_system_error(__e); 216e4b17023SJohn Marino } 217e4b17023SJohn Marino 218e4b17023SJohn Marino bool 219e4b17023SJohn Marino try_lock() noexcept 220e4b17023SJohn Marino { 221e4b17023SJohn Marino // XXX EINVAL, EAGAIN, EBUSY 222e4b17023SJohn Marino return !__gthread_recursive_mutex_trylock(&_M_mutex); 223e4b17023SJohn Marino } 224e4b17023SJohn Marino 225e4b17023SJohn Marino void 226e4b17023SJohn Marino unlock() 227e4b17023SJohn Marino { 228e4b17023SJohn Marino // XXX EINVAL, EAGAIN, EBUSY 229e4b17023SJohn Marino __gthread_recursive_mutex_unlock(&_M_mutex); 230e4b17023SJohn Marino } 231e4b17023SJohn Marino 232e4b17023SJohn Marino native_handle_type 233e4b17023SJohn Marino native_handle() 234e4b17023SJohn Marino { return &_M_mutex; } 235e4b17023SJohn Marino }; 236e4b17023SJohn Marino 237e4b17023SJohn Marino#if _GTHREAD_USE_MUTEX_TIMEDLOCK 238e4b17023SJohn Marino /// timed_mutex 239e4b17023SJohn Marino class timed_mutex : private __mutex_base 240e4b17023SJohn Marino { 241e4b17023SJohn Marino#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC 242e4b17023SJohn Marino typedef chrono::steady_clock __clock_t; 243e4b17023SJohn Marino#else 244e4b17023SJohn Marino typedef chrono::high_resolution_clock __clock_t; 245e4b17023SJohn Marino#endif 246e4b17023SJohn Marino 247e4b17023SJohn Marino public: 248e4b17023SJohn Marino typedef __native_type* native_handle_type; 249e4b17023SJohn Marino 250e4b17023SJohn Marino timed_mutex() = default; 251e4b17023SJohn Marino ~timed_mutex() = default; 252e4b17023SJohn Marino 253e4b17023SJohn Marino timed_mutex(const timed_mutex&) = delete; 254e4b17023SJohn Marino timed_mutex& operator=(const timed_mutex&) = delete; 255e4b17023SJohn Marino 256e4b17023SJohn Marino void 257e4b17023SJohn Marino lock() 258e4b17023SJohn Marino { 259e4b17023SJohn Marino int __e = __gthread_mutex_lock(&_M_mutex); 260e4b17023SJohn Marino 261e4b17023SJohn Marino // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 262e4b17023SJohn Marino if (__e) 263e4b17023SJohn Marino __throw_system_error(__e); 264e4b17023SJohn Marino } 265e4b17023SJohn Marino 266e4b17023SJohn Marino bool 267e4b17023SJohn Marino try_lock() noexcept 268e4b17023SJohn Marino { 269e4b17023SJohn Marino // XXX EINVAL, EAGAIN, EBUSY 270e4b17023SJohn Marino return !__gthread_mutex_trylock(&_M_mutex); 271e4b17023SJohn Marino } 272e4b17023SJohn Marino 273e4b17023SJohn Marino template <class _Rep, class _Period> 274e4b17023SJohn Marino bool 275e4b17023SJohn Marino try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 276e4b17023SJohn Marino { return __try_lock_for_impl(__rtime); } 277e4b17023SJohn Marino 278e4b17023SJohn Marino template <class _Clock, class _Duration> 279e4b17023SJohn Marino bool 280e4b17023SJohn Marino try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 281e4b17023SJohn Marino { 282e4b17023SJohn Marino chrono::time_point<_Clock, chrono::seconds> __s = 283e4b17023SJohn Marino chrono::time_point_cast<chrono::seconds>(__atime); 284e4b17023SJohn Marino 285e4b17023SJohn Marino chrono::nanoseconds __ns = 286e4b17023SJohn Marino chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 287e4b17023SJohn Marino 288e4b17023SJohn Marino __gthread_time_t __ts = { 289e4b17023SJohn Marino static_cast<std::time_t>(__s.time_since_epoch().count()), 290e4b17023SJohn Marino static_cast<long>(__ns.count()) 291e4b17023SJohn Marino }; 292e4b17023SJohn Marino 293e4b17023SJohn Marino return !__gthread_mutex_timedlock(&_M_mutex, &__ts); 294e4b17023SJohn Marino } 295e4b17023SJohn Marino 296e4b17023SJohn Marino void 297e4b17023SJohn Marino unlock() 298e4b17023SJohn Marino { 299e4b17023SJohn Marino // XXX EINVAL, EAGAIN, EBUSY 300e4b17023SJohn Marino __gthread_mutex_unlock(&_M_mutex); 301e4b17023SJohn Marino } 302e4b17023SJohn Marino 303e4b17023SJohn Marino native_handle_type 304e4b17023SJohn Marino native_handle() 305e4b17023SJohn Marino { return &_M_mutex; } 306e4b17023SJohn Marino 307e4b17023SJohn Marino private: 308e4b17023SJohn Marino template<typename _Rep, typename _Period> 309e4b17023SJohn Marino typename enable_if< 310e4b17023SJohn Marino ratio_less_equal<__clock_t::period, _Period>::value, bool>::type 311e4b17023SJohn Marino __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime) 312e4b17023SJohn Marino { 313e4b17023SJohn Marino __clock_t::time_point __atime = __clock_t::now() 314e4b17023SJohn Marino + chrono::duration_cast<__clock_t::duration>(__rtime); 315e4b17023SJohn Marino 316e4b17023SJohn Marino return try_lock_until(__atime); 317e4b17023SJohn Marino } 318e4b17023SJohn Marino 319e4b17023SJohn Marino template <typename _Rep, typename _Period> 320e4b17023SJohn Marino typename enable_if< 321e4b17023SJohn Marino !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type 322e4b17023SJohn Marino __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime) 323e4b17023SJohn Marino { 324e4b17023SJohn Marino __clock_t::time_point __atime = __clock_t::now() 325e4b17023SJohn Marino + ++chrono::duration_cast<__clock_t::duration>(__rtime); 326e4b17023SJohn Marino 327e4b17023SJohn Marino return try_lock_until(__atime); 328e4b17023SJohn Marino } 329e4b17023SJohn Marino }; 330e4b17023SJohn Marino 331e4b17023SJohn Marino /// recursive_timed_mutex 332e4b17023SJohn Marino class recursive_timed_mutex : private __recursive_mutex_base 333e4b17023SJohn Marino { 334e4b17023SJohn Marino#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC 335e4b17023SJohn Marino typedef chrono::steady_clock __clock_t; 336e4b17023SJohn Marino#else 337e4b17023SJohn Marino typedef chrono::high_resolution_clock __clock_t; 338e4b17023SJohn Marino#endif 339e4b17023SJohn Marino 340e4b17023SJohn Marino public: 341e4b17023SJohn Marino typedef __native_type* native_handle_type; 342e4b17023SJohn Marino 343e4b17023SJohn Marino recursive_timed_mutex() = default; 344e4b17023SJohn Marino ~recursive_timed_mutex() = default; 345e4b17023SJohn Marino 346e4b17023SJohn Marino recursive_timed_mutex(const recursive_timed_mutex&) = delete; 347e4b17023SJohn Marino recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 348e4b17023SJohn Marino 349e4b17023SJohn Marino void 350e4b17023SJohn Marino lock() 351e4b17023SJohn Marino { 352e4b17023SJohn Marino int __e = __gthread_recursive_mutex_lock(&_M_mutex); 353e4b17023SJohn Marino 354e4b17023SJohn Marino // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 355e4b17023SJohn Marino if (__e) 356e4b17023SJohn Marino __throw_system_error(__e); 357e4b17023SJohn Marino } 358e4b17023SJohn Marino 359e4b17023SJohn Marino bool 360e4b17023SJohn Marino try_lock() noexcept 361e4b17023SJohn Marino { 362e4b17023SJohn Marino // XXX EINVAL, EAGAIN, EBUSY 363e4b17023SJohn Marino return !__gthread_recursive_mutex_trylock(&_M_mutex); 364e4b17023SJohn Marino } 365e4b17023SJohn Marino 366e4b17023SJohn Marino template <class _Rep, class _Period> 367e4b17023SJohn Marino bool 368e4b17023SJohn Marino try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 369e4b17023SJohn Marino { return __try_lock_for_impl(__rtime); } 370e4b17023SJohn Marino 371e4b17023SJohn Marino template <class _Clock, class _Duration> 372e4b17023SJohn Marino bool 373e4b17023SJohn Marino try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 374e4b17023SJohn Marino { 375e4b17023SJohn Marino chrono::time_point<_Clock, chrono::seconds> __s = 376e4b17023SJohn Marino chrono::time_point_cast<chrono::seconds>(__atime); 377e4b17023SJohn Marino 378e4b17023SJohn Marino chrono::nanoseconds __ns = 379e4b17023SJohn Marino chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 380e4b17023SJohn Marino 381e4b17023SJohn Marino __gthread_time_t __ts = { 382e4b17023SJohn Marino static_cast<std::time_t>(__s.time_since_epoch().count()), 383e4b17023SJohn Marino static_cast<long>(__ns.count()) 384e4b17023SJohn Marino }; 385e4b17023SJohn Marino 386e4b17023SJohn Marino return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); 387e4b17023SJohn Marino } 388e4b17023SJohn Marino 389e4b17023SJohn Marino void 390e4b17023SJohn Marino unlock() 391e4b17023SJohn Marino { 392e4b17023SJohn Marino // XXX EINVAL, EAGAIN, EBUSY 393e4b17023SJohn Marino __gthread_recursive_mutex_unlock(&_M_mutex); 394e4b17023SJohn Marino } 395e4b17023SJohn Marino 396e4b17023SJohn Marino native_handle_type 397e4b17023SJohn Marino native_handle() 398e4b17023SJohn Marino { return &_M_mutex; } 399e4b17023SJohn Marino 400e4b17023SJohn Marino private: 401e4b17023SJohn Marino template<typename _Rep, typename _Period> 402e4b17023SJohn Marino typename enable_if< 403e4b17023SJohn Marino ratio_less_equal<__clock_t::period, _Period>::value, bool>::type 404e4b17023SJohn Marino __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime) 405e4b17023SJohn Marino { 406e4b17023SJohn Marino __clock_t::time_point __atime = __clock_t::now() 407e4b17023SJohn Marino + chrono::duration_cast<__clock_t::duration>(__rtime); 408e4b17023SJohn Marino 409e4b17023SJohn Marino return try_lock_until(__atime); 410e4b17023SJohn Marino } 411e4b17023SJohn Marino 412e4b17023SJohn Marino template <typename _Rep, typename _Period> 413e4b17023SJohn Marino typename enable_if< 414e4b17023SJohn Marino !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type 415e4b17023SJohn Marino __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime) 416e4b17023SJohn Marino { 417e4b17023SJohn Marino __clock_t::time_point __atime = __clock_t::now() 418e4b17023SJohn Marino + ++chrono::duration_cast<__clock_t::duration>(__rtime); 419e4b17023SJohn Marino 420e4b17023SJohn Marino return try_lock_until(__atime); 421e4b17023SJohn Marino } 422e4b17023SJohn Marino }; 423e4b17023SJohn Marino#endif 424*5ce9237cSJohn Marino#endif // _GLIBCXX_HAS_GTHREADS 425e4b17023SJohn Marino 426e4b17023SJohn Marino /// Do not acquire ownership of the mutex. 427e4b17023SJohn Marino struct defer_lock_t { }; 428e4b17023SJohn Marino 429e4b17023SJohn Marino /// Try to acquire ownership of the mutex without blocking. 430e4b17023SJohn Marino struct try_to_lock_t { }; 431e4b17023SJohn Marino 432e4b17023SJohn Marino /// Assume the calling thread has already obtained mutex ownership 433e4b17023SJohn Marino /// and manage it. 434e4b17023SJohn Marino struct adopt_lock_t { }; 435e4b17023SJohn Marino 436e4b17023SJohn Marino constexpr defer_lock_t defer_lock { }; 437e4b17023SJohn Marino constexpr try_to_lock_t try_to_lock { }; 438e4b17023SJohn Marino constexpr adopt_lock_t adopt_lock { }; 439e4b17023SJohn Marino 440e4b17023SJohn Marino /// @brief Scoped lock idiom. 441e4b17023SJohn Marino // Acquire the mutex here with a constructor call, then release with 442e4b17023SJohn Marino // the destructor call in accordance with RAII style. 443e4b17023SJohn Marino template<typename _Mutex> 444e4b17023SJohn Marino class lock_guard 445e4b17023SJohn Marino { 446e4b17023SJohn Marino public: 447e4b17023SJohn Marino typedef _Mutex mutex_type; 448e4b17023SJohn Marino 449e4b17023SJohn Marino explicit lock_guard(mutex_type& __m) : _M_device(__m) 450e4b17023SJohn Marino { _M_device.lock(); } 451e4b17023SJohn Marino 452e4b17023SJohn Marino lock_guard(mutex_type& __m, adopt_lock_t) : _M_device(__m) 453e4b17023SJohn Marino { } // calling thread owns mutex 454e4b17023SJohn Marino 455e4b17023SJohn Marino ~lock_guard() 456e4b17023SJohn Marino { _M_device.unlock(); } 457e4b17023SJohn Marino 458e4b17023SJohn Marino lock_guard(const lock_guard&) = delete; 459e4b17023SJohn Marino lock_guard& operator=(const lock_guard&) = delete; 460e4b17023SJohn Marino 461e4b17023SJohn Marino private: 462e4b17023SJohn Marino mutex_type& _M_device; 463e4b17023SJohn Marino }; 464e4b17023SJohn Marino 465e4b17023SJohn Marino /// unique_lock 466e4b17023SJohn Marino template<typename _Mutex> 467e4b17023SJohn Marino class unique_lock 468e4b17023SJohn Marino { 469e4b17023SJohn Marino public: 470e4b17023SJohn Marino typedef _Mutex mutex_type; 471e4b17023SJohn Marino 472e4b17023SJohn Marino unique_lock() noexcept 473e4b17023SJohn Marino : _M_device(0), _M_owns(false) 474e4b17023SJohn Marino { } 475e4b17023SJohn Marino 476e4b17023SJohn Marino explicit unique_lock(mutex_type& __m) 477e4b17023SJohn Marino : _M_device(&__m), _M_owns(false) 478e4b17023SJohn Marino { 479e4b17023SJohn Marino lock(); 480e4b17023SJohn Marino _M_owns = true; 481e4b17023SJohn Marino } 482e4b17023SJohn Marino 483e4b17023SJohn Marino unique_lock(mutex_type& __m, defer_lock_t) noexcept 484e4b17023SJohn Marino : _M_device(&__m), _M_owns(false) 485e4b17023SJohn Marino { } 486e4b17023SJohn Marino 487e4b17023SJohn Marino unique_lock(mutex_type& __m, try_to_lock_t) 488e4b17023SJohn Marino : _M_device(&__m), _M_owns(_M_device->try_lock()) 489e4b17023SJohn Marino { } 490e4b17023SJohn Marino 491e4b17023SJohn Marino unique_lock(mutex_type& __m, adopt_lock_t) 492e4b17023SJohn Marino : _M_device(&__m), _M_owns(true) 493e4b17023SJohn Marino { 494e4b17023SJohn Marino // XXX calling thread owns mutex 495e4b17023SJohn Marino } 496e4b17023SJohn Marino 497e4b17023SJohn Marino template<typename _Clock, typename _Duration> 498e4b17023SJohn Marino unique_lock(mutex_type& __m, 499e4b17023SJohn Marino const chrono::time_point<_Clock, _Duration>& __atime) 500e4b17023SJohn Marino : _M_device(&__m), _M_owns(_M_device->try_lock_until(__atime)) 501e4b17023SJohn Marino { } 502e4b17023SJohn Marino 503e4b17023SJohn Marino template<typename _Rep, typename _Period> 504e4b17023SJohn Marino unique_lock(mutex_type& __m, 505e4b17023SJohn Marino const chrono::duration<_Rep, _Period>& __rtime) 506e4b17023SJohn Marino : _M_device(&__m), _M_owns(_M_device->try_lock_for(__rtime)) 507e4b17023SJohn Marino { } 508e4b17023SJohn Marino 509e4b17023SJohn Marino ~unique_lock() 510e4b17023SJohn Marino { 511e4b17023SJohn Marino if (_M_owns) 512e4b17023SJohn Marino unlock(); 513e4b17023SJohn Marino } 514e4b17023SJohn Marino 515e4b17023SJohn Marino unique_lock(const unique_lock&) = delete; 516e4b17023SJohn Marino unique_lock& operator=(const unique_lock&) = delete; 517e4b17023SJohn Marino 518e4b17023SJohn Marino unique_lock(unique_lock&& __u) noexcept 519e4b17023SJohn Marino : _M_device(__u._M_device), _M_owns(__u._M_owns) 520e4b17023SJohn Marino { 521e4b17023SJohn Marino __u._M_device = 0; 522e4b17023SJohn Marino __u._M_owns = false; 523e4b17023SJohn Marino } 524e4b17023SJohn Marino 525e4b17023SJohn Marino unique_lock& operator=(unique_lock&& __u) noexcept 526e4b17023SJohn Marino { 527e4b17023SJohn Marino if(_M_owns) 528e4b17023SJohn Marino unlock(); 529e4b17023SJohn Marino 530e4b17023SJohn Marino unique_lock(std::move(__u)).swap(*this); 531e4b17023SJohn Marino 532e4b17023SJohn Marino __u._M_device = 0; 533e4b17023SJohn Marino __u._M_owns = false; 534e4b17023SJohn Marino 535e4b17023SJohn Marino return *this; 536e4b17023SJohn Marino } 537e4b17023SJohn Marino 538e4b17023SJohn Marino void 539e4b17023SJohn Marino lock() 540e4b17023SJohn Marino { 541e4b17023SJohn Marino if (!_M_device) 542e4b17023SJohn Marino __throw_system_error(int(errc::operation_not_permitted)); 543e4b17023SJohn Marino else if (_M_owns) 544e4b17023SJohn Marino __throw_system_error(int(errc::resource_deadlock_would_occur)); 545e4b17023SJohn Marino else 546e4b17023SJohn Marino { 547e4b17023SJohn Marino _M_device->lock(); 548e4b17023SJohn Marino _M_owns = true; 549e4b17023SJohn Marino } 550e4b17023SJohn Marino } 551e4b17023SJohn Marino 552e4b17023SJohn Marino bool 553e4b17023SJohn Marino try_lock() 554e4b17023SJohn Marino { 555e4b17023SJohn Marino if (!_M_device) 556e4b17023SJohn Marino __throw_system_error(int(errc::operation_not_permitted)); 557e4b17023SJohn Marino else if (_M_owns) 558e4b17023SJohn Marino __throw_system_error(int(errc::resource_deadlock_would_occur)); 559e4b17023SJohn Marino else 560e4b17023SJohn Marino { 561e4b17023SJohn Marino _M_owns = _M_device->try_lock(); 562e4b17023SJohn Marino return _M_owns; 563e4b17023SJohn Marino } 564e4b17023SJohn Marino } 565e4b17023SJohn Marino 566e4b17023SJohn Marino template<typename _Clock, typename _Duration> 567e4b17023SJohn Marino bool 568e4b17023SJohn Marino try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 569e4b17023SJohn Marino { 570e4b17023SJohn Marino if (!_M_device) 571e4b17023SJohn Marino __throw_system_error(int(errc::operation_not_permitted)); 572e4b17023SJohn Marino else if (_M_owns) 573e4b17023SJohn Marino __throw_system_error(int(errc::resource_deadlock_would_occur)); 574e4b17023SJohn Marino else 575e4b17023SJohn Marino { 576e4b17023SJohn Marino _M_owns = _M_device->try_lock_until(__atime); 577e4b17023SJohn Marino return _M_owns; 578e4b17023SJohn Marino } 579e4b17023SJohn Marino } 580e4b17023SJohn Marino 581e4b17023SJohn Marino template<typename _Rep, typename _Period> 582e4b17023SJohn Marino bool 583e4b17023SJohn Marino try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 584e4b17023SJohn Marino { 585e4b17023SJohn Marino if (!_M_device) 586e4b17023SJohn Marino __throw_system_error(int(errc::operation_not_permitted)); 587e4b17023SJohn Marino else if (_M_owns) 588e4b17023SJohn Marino __throw_system_error(int(errc::resource_deadlock_would_occur)); 589e4b17023SJohn Marino else 590e4b17023SJohn Marino { 591e4b17023SJohn Marino _M_owns = _M_device->try_lock_for(__rtime); 592e4b17023SJohn Marino return _M_owns; 593e4b17023SJohn Marino } 594e4b17023SJohn Marino } 595e4b17023SJohn Marino 596e4b17023SJohn Marino void 597e4b17023SJohn Marino unlock() 598e4b17023SJohn Marino { 599e4b17023SJohn Marino if (!_M_owns) 600e4b17023SJohn Marino __throw_system_error(int(errc::operation_not_permitted)); 601e4b17023SJohn Marino else if (_M_device) 602e4b17023SJohn Marino { 603e4b17023SJohn Marino _M_device->unlock(); 604e4b17023SJohn Marino _M_owns = false; 605e4b17023SJohn Marino } 606e4b17023SJohn Marino } 607e4b17023SJohn Marino 608e4b17023SJohn Marino void 609e4b17023SJohn Marino swap(unique_lock& __u) noexcept 610e4b17023SJohn Marino { 611e4b17023SJohn Marino std::swap(_M_device, __u._M_device); 612e4b17023SJohn Marino std::swap(_M_owns, __u._M_owns); 613e4b17023SJohn Marino } 614e4b17023SJohn Marino 615e4b17023SJohn Marino mutex_type* 616e4b17023SJohn Marino release() noexcept 617e4b17023SJohn Marino { 618e4b17023SJohn Marino mutex_type* __ret = _M_device; 619e4b17023SJohn Marino _M_device = 0; 620e4b17023SJohn Marino _M_owns = false; 621e4b17023SJohn Marino return __ret; 622e4b17023SJohn Marino } 623e4b17023SJohn Marino 624e4b17023SJohn Marino bool 625e4b17023SJohn Marino owns_lock() const noexcept 626e4b17023SJohn Marino { return _M_owns; } 627e4b17023SJohn Marino 628e4b17023SJohn Marino explicit operator bool() const noexcept 629e4b17023SJohn Marino { return owns_lock(); } 630e4b17023SJohn Marino 631e4b17023SJohn Marino mutex_type* 632e4b17023SJohn Marino mutex() const noexcept 633e4b17023SJohn Marino { return _M_device; } 634e4b17023SJohn Marino 635e4b17023SJohn Marino private: 636e4b17023SJohn Marino mutex_type* _M_device; 637e4b17023SJohn Marino bool _M_owns; // XXX use atomic_bool 638e4b17023SJohn Marino }; 639e4b17023SJohn Marino 640e4b17023SJohn Marino /// Partial specialization for unique_lock objects. 641e4b17023SJohn Marino template<typename _Mutex> 642e4b17023SJohn Marino inline void 643e4b17023SJohn Marino swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept 644e4b17023SJohn Marino { __x.swap(__y); } 645e4b17023SJohn Marino 646e4b17023SJohn Marino template<int _Idx> 647e4b17023SJohn Marino struct __unlock_impl 648e4b17023SJohn Marino { 649e4b17023SJohn Marino template<typename... _Lock> 650e4b17023SJohn Marino static void 651e4b17023SJohn Marino __do_unlock(tuple<_Lock&...>& __locks) 652e4b17023SJohn Marino { 653e4b17023SJohn Marino std::get<_Idx>(__locks).unlock(); 654e4b17023SJohn Marino __unlock_impl<_Idx - 1>::__do_unlock(__locks); 655e4b17023SJohn Marino } 656e4b17023SJohn Marino }; 657e4b17023SJohn Marino 658e4b17023SJohn Marino template<> 659e4b17023SJohn Marino struct __unlock_impl<-1> 660e4b17023SJohn Marino { 661e4b17023SJohn Marino template<typename... _Lock> 662e4b17023SJohn Marino static void 663e4b17023SJohn Marino __do_unlock(tuple<_Lock&...>&) 664e4b17023SJohn Marino { } 665e4b17023SJohn Marino }; 666e4b17023SJohn Marino 667e4b17023SJohn Marino template<typename _Lock> 668e4b17023SJohn Marino unique_lock<_Lock> 669e4b17023SJohn Marino __try_to_lock(_Lock& __l) 670e4b17023SJohn Marino { return unique_lock<_Lock>(__l, try_to_lock); } 671e4b17023SJohn Marino 672e4b17023SJohn Marino template<int _Idx, bool _Continue = true> 673e4b17023SJohn Marino struct __try_lock_impl 674e4b17023SJohn Marino { 675e4b17023SJohn Marino template<typename... _Lock> 676e4b17023SJohn Marino static void 677e4b17023SJohn Marino __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 678e4b17023SJohn Marino { 679e4b17023SJohn Marino __idx = _Idx; 680e4b17023SJohn Marino auto __lock = __try_to_lock(std::get<_Idx>(__locks)); 681e4b17023SJohn Marino if (__lock.owns_lock()) 682e4b17023SJohn Marino { 683e4b17023SJohn Marino __try_lock_impl<_Idx + 1, _Idx + 2 < sizeof...(_Lock)>:: 684e4b17023SJohn Marino __do_try_lock(__locks, __idx); 685e4b17023SJohn Marino if (__idx == -1) 686e4b17023SJohn Marino __lock.release(); 687e4b17023SJohn Marino } 688e4b17023SJohn Marino } 689e4b17023SJohn Marino }; 690e4b17023SJohn Marino 691e4b17023SJohn Marino template<int _Idx> 692e4b17023SJohn Marino struct __try_lock_impl<_Idx, false> 693e4b17023SJohn Marino { 694e4b17023SJohn Marino template<typename... _Lock> 695e4b17023SJohn Marino static void 696e4b17023SJohn Marino __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 697e4b17023SJohn Marino { 698e4b17023SJohn Marino __idx = _Idx; 699e4b17023SJohn Marino auto __lock = __try_to_lock(std::get<_Idx>(__locks)); 700e4b17023SJohn Marino if (__lock.owns_lock()) 701e4b17023SJohn Marino { 702e4b17023SJohn Marino __idx = -1; 703e4b17023SJohn Marino __lock.release(); 704e4b17023SJohn Marino } 705e4b17023SJohn Marino } 706e4b17023SJohn Marino }; 707e4b17023SJohn Marino 708e4b17023SJohn Marino /** @brief Generic try_lock. 709e4b17023SJohn Marino * @param __l1 Meets Mutex requirements (try_lock() may throw). 710e4b17023SJohn Marino * @param __l2 Meets Mutex requirements (try_lock() may throw). 711e4b17023SJohn Marino * @param __l3 Meets Mutex requirements (try_lock() may throw). 712e4b17023SJohn Marino * @return Returns -1 if all try_lock() calls return true. Otherwise returns 713e4b17023SJohn Marino * a 0-based index corresponding to the argument that returned false. 714e4b17023SJohn Marino * @post Either all arguments are locked, or none will be. 715e4b17023SJohn Marino * 716e4b17023SJohn Marino * Sequentially calls try_lock() on each argument. 717e4b17023SJohn Marino */ 718e4b17023SJohn Marino template<typename _Lock1, typename _Lock2, typename... _Lock3> 719e4b17023SJohn Marino int 720e4b17023SJohn Marino try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3) 721e4b17023SJohn Marino { 722e4b17023SJohn Marino int __idx; 723e4b17023SJohn Marino auto __locks = std::tie(__l1, __l2, __l3...); 724e4b17023SJohn Marino __try 725e4b17023SJohn Marino { __try_lock_impl<0>::__do_try_lock(__locks, __idx); } 726e4b17023SJohn Marino __catch(...) 727e4b17023SJohn Marino { } 728e4b17023SJohn Marino return __idx; 729e4b17023SJohn Marino } 730e4b17023SJohn Marino 731e4b17023SJohn Marino /** @brief Generic lock. 732e4b17023SJohn Marino * @param __l1 Meets Mutex requirements (try_lock() may throw). 733e4b17023SJohn Marino * @param __l2 Meets Mutex requirements (try_lock() may throw). 734e4b17023SJohn Marino * @param __l3 Meets Mutex requirements (try_lock() may throw). 735e4b17023SJohn Marino * @throw An exception thrown by an argument's lock() or try_lock() member. 736e4b17023SJohn Marino * @post All arguments are locked. 737e4b17023SJohn Marino * 738e4b17023SJohn Marino * All arguments are locked via a sequence of calls to lock(), try_lock() 739e4b17023SJohn Marino * and unlock(). If the call exits via an exception any locks that were 740e4b17023SJohn Marino * obtained will be released. 741e4b17023SJohn Marino */ 742e4b17023SJohn Marino template<typename _L1, typename _L2, typename ..._L3> 743e4b17023SJohn Marino void 744e4b17023SJohn Marino lock(_L1& __l1, _L2& __l2, _L3&... __l3) 745e4b17023SJohn Marino { 746e4b17023SJohn Marino while (true) 747e4b17023SJohn Marino { 748e4b17023SJohn Marino unique_lock<_L1> __first(__l1); 749e4b17023SJohn Marino int __idx; 750e4b17023SJohn Marino auto __locks = std::tie(__l2, __l3...); 751e4b17023SJohn Marino __try_lock_impl<0, sizeof...(_L3)>::__do_try_lock(__locks, __idx); 752e4b17023SJohn Marino if (__idx == -1) 753e4b17023SJohn Marino { 754e4b17023SJohn Marino __first.release(); 755e4b17023SJohn Marino return; 756e4b17023SJohn Marino } 757e4b17023SJohn Marino } 758e4b17023SJohn Marino } 759e4b17023SJohn Marino 760*5ce9237cSJohn Marino#ifdef _GLIBCXX_HAS_GTHREADS 761e4b17023SJohn Marino /// once_flag 762e4b17023SJohn Marino struct once_flag 763e4b17023SJohn Marino { 764e4b17023SJohn Marino private: 765e4b17023SJohn Marino typedef __gthread_once_t __native_type; 766e4b17023SJohn Marino __native_type _M_once = __GTHREAD_ONCE_INIT; 767e4b17023SJohn Marino 768e4b17023SJohn Marino public: 769e4b17023SJohn Marino /// Constructor 770e4b17023SJohn Marino constexpr once_flag() noexcept = default; 771e4b17023SJohn Marino 772e4b17023SJohn Marino /// Deleted copy constructor 773e4b17023SJohn Marino once_flag(const once_flag&) = delete; 774e4b17023SJohn Marino /// Deleted assignment operator 775e4b17023SJohn Marino once_flag& operator=(const once_flag&) = delete; 776e4b17023SJohn Marino 777e4b17023SJohn Marino template<typename _Callable, typename... _Args> 778e4b17023SJohn Marino friend void 779e4b17023SJohn Marino call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); 780e4b17023SJohn Marino }; 781e4b17023SJohn Marino 782e4b17023SJohn Marino#ifdef _GLIBCXX_HAVE_TLS 783e4b17023SJohn Marino extern __thread void* __once_callable; 784e4b17023SJohn Marino extern __thread void (*__once_call)(); 785e4b17023SJohn Marino 786e4b17023SJohn Marino template<typename _Callable> 787e4b17023SJohn Marino inline void 788e4b17023SJohn Marino __once_call_impl() 789e4b17023SJohn Marino { 790e4b17023SJohn Marino (*(_Callable*)__once_callable)(); 791e4b17023SJohn Marino } 792e4b17023SJohn Marino#else 793e4b17023SJohn Marino extern function<void()> __once_functor; 794e4b17023SJohn Marino 795e4b17023SJohn Marino extern void 796e4b17023SJohn Marino __set_once_functor_lock_ptr(unique_lock<mutex>*); 797e4b17023SJohn Marino 798e4b17023SJohn Marino extern mutex& 799e4b17023SJohn Marino __get_once_mutex(); 800e4b17023SJohn Marino#endif 801e4b17023SJohn Marino 802e4b17023SJohn Marino extern "C" void __once_proxy(void); 803e4b17023SJohn Marino 804e4b17023SJohn Marino /// call_once 805e4b17023SJohn Marino template<typename _Callable, typename... _Args> 806e4b17023SJohn Marino void 807e4b17023SJohn Marino call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) 808e4b17023SJohn Marino { 809e4b17023SJohn Marino#ifdef _GLIBCXX_HAVE_TLS 810e4b17023SJohn Marino auto __bound_functor = std::__bind_simple(std::forward<_Callable>(__f), 811e4b17023SJohn Marino std::forward<_Args>(__args)...); 812e4b17023SJohn Marino __once_callable = &__bound_functor; 813e4b17023SJohn Marino __once_call = &__once_call_impl<decltype(__bound_functor)>; 814e4b17023SJohn Marino#else 815e4b17023SJohn Marino unique_lock<mutex> __functor_lock(__get_once_mutex()); 816e4b17023SJohn Marino auto __callable = std::__bind_simple(std::forward<_Callable>(__f), 817e4b17023SJohn Marino std::forward<_Args>(__args)...); 818e4b17023SJohn Marino __once_functor = [&]() { __callable(); }; 819e4b17023SJohn Marino __set_once_functor_lock_ptr(&__functor_lock); 820e4b17023SJohn Marino#endif 821e4b17023SJohn Marino 822e4b17023SJohn Marino int __e = __gthread_once(&(__once._M_once), &__once_proxy); 823e4b17023SJohn Marino 824e4b17023SJohn Marino#ifndef _GLIBCXX_HAVE_TLS 825e4b17023SJohn Marino if (__functor_lock) 826e4b17023SJohn Marino __set_once_functor_lock_ptr(0); 827e4b17023SJohn Marino#endif 828e4b17023SJohn Marino 829e4b17023SJohn Marino if (__e) 830e4b17023SJohn Marino __throw_system_error(__e); 831e4b17023SJohn Marino } 832*5ce9237cSJohn Marino#endif // _GLIBCXX_HAS_GTHREADS 833e4b17023SJohn Marino 834e4b17023SJohn Marino // @} group mutexes 835e4b17023SJohn Marino_GLIBCXX_END_NAMESPACE_VERSION 836e4b17023SJohn Marino} // namespace 837e4b17023SJohn Marino 838*5ce9237cSJohn Marino#endif // _GLIBCXX_USE_C99_STDINT_TR1 839e4b17023SJohn Marino 840e4b17023SJohn Marino#endif // __GXX_EXPERIMENTAL_CXX0X__ 841e4b17023SJohn Marino 842e4b17023SJohn Marino#endif // _GLIBCXX_MUTEX 843