1e4b17023SJohn Marino// <condition_variable> -*- C++ -*- 2e4b17023SJohn Marino 3e4b17023SJohn Marino// Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. 4e4b17023SJohn Marino// 5e4b17023SJohn Marino// This file is part of the GNU ISO C++ Library. This library is free 6e4b17023SJohn Marino// software; you can redistribute it and/or modify it under the 7e4b17023SJohn Marino// terms of the GNU General Public License as published by the 8e4b17023SJohn Marino// Free Software Foundation; either version 3, or (at your option) 9e4b17023SJohn Marino// any later version. 10e4b17023SJohn Marino 11e4b17023SJohn Marino// This library is distributed in the hope that it will be useful, 12e4b17023SJohn Marino// but WITHOUT ANY WARRANTY; without even the implied warranty of 13e4b17023SJohn Marino// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14e4b17023SJohn Marino// GNU General Public License for more details. 15e4b17023SJohn Marino 16e4b17023SJohn Marino// Under Section 7 of GPL version 3, you are granted additional 17e4b17023SJohn Marino// permissions described in the GCC Runtime Library Exception, version 18e4b17023SJohn Marino// 3.1, as published by the Free Software Foundation. 19e4b17023SJohn Marino 20e4b17023SJohn Marino// You should have received a copy of the GNU General Public License and 21e4b17023SJohn Marino// a copy of the GCC Runtime Library Exception along with this program; 22e4b17023SJohn Marino// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23e4b17023SJohn Marino// <http://www.gnu.org/licenses/>. 24e4b17023SJohn Marino 25e4b17023SJohn Marino/** @file include/condition_variable 26e4b17023SJohn Marino * This is a Standard C++ Library header. 27e4b17023SJohn Marino */ 28e4b17023SJohn Marino 29e4b17023SJohn Marino#ifndef _GLIBCXX_CONDITION_VARIABLE 30e4b17023SJohn Marino#define _GLIBCXX_CONDITION_VARIABLE 1 31e4b17023SJohn Marino 32e4b17023SJohn Marino#pragma GCC system_header 33e4b17023SJohn Marino 34e4b17023SJohn Marino#ifndef __GXX_EXPERIMENTAL_CXX0X__ 35e4b17023SJohn Marino# include <bits/c++0x_warning.h> 36e4b17023SJohn Marino#else 37e4b17023SJohn Marino 38e4b17023SJohn Marino#include <chrono> 39e4b17023SJohn Marino#include <mutex> // unique_lock 40e4b17023SJohn Marino 41e4b17023SJohn Marino#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) 42e4b17023SJohn Marino 43e4b17023SJohn Marinonamespace std _GLIBCXX_VISIBILITY(default) 44e4b17023SJohn Marino{ 45e4b17023SJohn Marino_GLIBCXX_BEGIN_NAMESPACE_VERSION 46e4b17023SJohn Marino 47e4b17023SJohn Marino /** 48e4b17023SJohn Marino * @defgroup condition_variables Condition Variables 49e4b17023SJohn Marino * @ingroup concurrency 50e4b17023SJohn Marino * 51e4b17023SJohn Marino * Classes for condition_variable support. 52e4b17023SJohn Marino * @{ 53e4b17023SJohn Marino */ 54e4b17023SJohn Marino 55e4b17023SJohn Marino /// cv_status 56e4b17023SJohn Marino enum class cv_status { no_timeout, timeout }; 57e4b17023SJohn Marino 58e4b17023SJohn Marino /// condition_variable 59e4b17023SJohn Marino class condition_variable 60e4b17023SJohn Marino { 61e4b17023SJohn Marino typedef chrono::system_clock __clock_t; 62e4b17023SJohn Marino typedef __gthread_cond_t __native_type; 63e4b17023SJohn Marino 64e4b17023SJohn Marino#ifdef __GTHREAD_COND_INIT 65e4b17023SJohn Marino __native_type _M_cond = __GTHREAD_COND_INIT; 66e4b17023SJohn Marino#else 67e4b17023SJohn Marino __native_type _M_cond; 68e4b17023SJohn Marino#endif 69e4b17023SJohn Marino 70e4b17023SJohn Marino public: 71e4b17023SJohn Marino typedef __native_type* native_handle_type; 72e4b17023SJohn Marino 73e4b17023SJohn Marino condition_variable() noexcept; 74e4b17023SJohn Marino ~condition_variable() noexcept; 75e4b17023SJohn Marino 76e4b17023SJohn Marino condition_variable(const condition_variable&) = delete; 77e4b17023SJohn Marino condition_variable& operator=(const condition_variable&) = delete; 78e4b17023SJohn Marino 79e4b17023SJohn Marino void 80e4b17023SJohn Marino notify_one() noexcept; 81e4b17023SJohn Marino 82e4b17023SJohn Marino void 83e4b17023SJohn Marino notify_all() noexcept; 84e4b17023SJohn Marino 85e4b17023SJohn Marino void 86e4b17023SJohn Marino wait(unique_lock<mutex>& __lock); 87e4b17023SJohn Marino 88e4b17023SJohn Marino template<typename _Predicate> 89e4b17023SJohn Marino void 90e4b17023SJohn Marino wait(unique_lock<mutex>& __lock, _Predicate __p) 91e4b17023SJohn Marino { 92e4b17023SJohn Marino while (!__p()) 93e4b17023SJohn Marino wait(__lock); 94e4b17023SJohn Marino } 95e4b17023SJohn Marino 96e4b17023SJohn Marino template<typename _Duration> 97e4b17023SJohn Marino cv_status 98e4b17023SJohn Marino wait_until(unique_lock<mutex>& __lock, 99e4b17023SJohn Marino const chrono::time_point<__clock_t, _Duration>& __atime) 100e4b17023SJohn Marino { return __wait_until_impl(__lock, __atime); } 101e4b17023SJohn Marino 102e4b17023SJohn Marino template<typename _Clock, typename _Duration> 103e4b17023SJohn Marino cv_status 104e4b17023SJohn Marino wait_until(unique_lock<mutex>& __lock, 105e4b17023SJohn Marino const chrono::time_point<_Clock, _Duration>& __atime) 106e4b17023SJohn Marino { 107e4b17023SJohn Marino // DR 887 - Sync unknown clock to known clock. 108e4b17023SJohn Marino const typename _Clock::time_point __c_entry = _Clock::now(); 109e4b17023SJohn Marino const __clock_t::time_point __s_entry = __clock_t::now(); 110*5ce9237cSJohn Marino const auto __delta = __atime - __c_entry; 111*5ce9237cSJohn Marino const auto __s_atime = __s_entry + __delta; 112e4b17023SJohn Marino 113e4b17023SJohn Marino return __wait_until_impl(__lock, __s_atime); 114e4b17023SJohn Marino } 115e4b17023SJohn Marino 116e4b17023SJohn Marino template<typename _Clock, typename _Duration, typename _Predicate> 117e4b17023SJohn Marino bool 118e4b17023SJohn Marino wait_until(unique_lock<mutex>& __lock, 119e4b17023SJohn Marino const chrono::time_point<_Clock, _Duration>& __atime, 120e4b17023SJohn Marino _Predicate __p) 121e4b17023SJohn Marino { 122e4b17023SJohn Marino while (!__p()) 123e4b17023SJohn Marino if (wait_until(__lock, __atime) == cv_status::timeout) 124e4b17023SJohn Marino return __p(); 125e4b17023SJohn Marino return true; 126e4b17023SJohn Marino } 127e4b17023SJohn Marino 128e4b17023SJohn Marino template<typename _Rep, typename _Period> 129e4b17023SJohn Marino cv_status 130e4b17023SJohn Marino wait_for(unique_lock<mutex>& __lock, 131e4b17023SJohn Marino const chrono::duration<_Rep, _Period>& __rtime) 132e4b17023SJohn Marino { return wait_until(__lock, __clock_t::now() + __rtime); } 133e4b17023SJohn Marino 134e4b17023SJohn Marino template<typename _Rep, typename _Period, typename _Predicate> 135e4b17023SJohn Marino bool 136e4b17023SJohn Marino wait_for(unique_lock<mutex>& __lock, 137e4b17023SJohn Marino const chrono::duration<_Rep, _Period>& __rtime, 138e4b17023SJohn Marino _Predicate __p) 139e4b17023SJohn Marino { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } 140e4b17023SJohn Marino 141e4b17023SJohn Marino native_handle_type 142e4b17023SJohn Marino native_handle() 143e4b17023SJohn Marino { return &_M_cond; } 144e4b17023SJohn Marino 145e4b17023SJohn Marino private: 146e4b17023SJohn Marino template<typename _Clock, typename _Duration> 147e4b17023SJohn Marino cv_status 148e4b17023SJohn Marino __wait_until_impl(unique_lock<mutex>& __lock, 149e4b17023SJohn Marino const chrono::time_point<_Clock, _Duration>& __atime) 150e4b17023SJohn Marino { 151e4b17023SJohn Marino chrono::time_point<__clock_t, chrono::seconds> __s = 152e4b17023SJohn Marino chrono::time_point_cast<chrono::seconds>(__atime); 153e4b17023SJohn Marino 154e4b17023SJohn Marino chrono::nanoseconds __ns = 155e4b17023SJohn Marino chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 156e4b17023SJohn Marino 157e4b17023SJohn Marino __gthread_time_t __ts = 158e4b17023SJohn Marino { 159e4b17023SJohn Marino static_cast<std::time_t>(__s.time_since_epoch().count()), 160e4b17023SJohn Marino static_cast<long>(__ns.count()) 161e4b17023SJohn Marino }; 162e4b17023SJohn Marino 163e4b17023SJohn Marino __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(), 164e4b17023SJohn Marino &__ts); 165e4b17023SJohn Marino 166e4b17023SJohn Marino return (_Clock::now() < __atime 167e4b17023SJohn Marino ? cv_status::no_timeout : cv_status::timeout); 168e4b17023SJohn Marino } 169e4b17023SJohn Marino }; 170e4b17023SJohn Marino 171e4b17023SJohn Marino /// condition_variable_any 172e4b17023SJohn Marino // Like above, but mutex is not required to have try_lock. 173e4b17023SJohn Marino class condition_variable_any 174e4b17023SJohn Marino { 175e4b17023SJohn Marino typedef chrono::system_clock __clock_t; 176e4b17023SJohn Marino condition_variable _M_cond; 177e4b17023SJohn Marino mutex _M_mutex; 178e4b17023SJohn Marino 179e4b17023SJohn Marino // scoped unlock - unlocks in ctor, re-locks in dtor 180e4b17023SJohn Marino template<typename _Lock> 181e4b17023SJohn Marino struct _Unlock 182e4b17023SJohn Marino { 183e4b17023SJohn Marino explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); } 184e4b17023SJohn Marino 185e4b17023SJohn Marino ~_Unlock() noexcept(false) 186e4b17023SJohn Marino { 187e4b17023SJohn Marino if (uncaught_exception()) 188e4b17023SJohn Marino __try { _M_lock.lock(); } __catch(...) { } 189e4b17023SJohn Marino else 190e4b17023SJohn Marino _M_lock.lock(); 191e4b17023SJohn Marino } 192e4b17023SJohn Marino 193e4b17023SJohn Marino _Unlock(const _Unlock&) = delete; 194e4b17023SJohn Marino _Unlock& operator=(const _Unlock&) = delete; 195e4b17023SJohn Marino 196e4b17023SJohn Marino _Lock& _M_lock; 197e4b17023SJohn Marino }; 198e4b17023SJohn Marino 199e4b17023SJohn Marino public: 200e4b17023SJohn Marino 201e4b17023SJohn Marino condition_variable_any() noexcept; 202e4b17023SJohn Marino ~condition_variable_any() noexcept; 203e4b17023SJohn Marino 204e4b17023SJohn Marino condition_variable_any(const condition_variable_any&) = delete; 205e4b17023SJohn Marino condition_variable_any& operator=(const condition_variable_any&) = delete; 206e4b17023SJohn Marino 207e4b17023SJohn Marino void 208e4b17023SJohn Marino notify_one() noexcept 209e4b17023SJohn Marino { 210e4b17023SJohn Marino lock_guard<mutex> __lock(_M_mutex); 211e4b17023SJohn Marino _M_cond.notify_one(); 212e4b17023SJohn Marino } 213e4b17023SJohn Marino 214e4b17023SJohn Marino void 215e4b17023SJohn Marino notify_all() noexcept 216e4b17023SJohn Marino { 217e4b17023SJohn Marino lock_guard<mutex> __lock(_M_mutex); 218e4b17023SJohn Marino _M_cond.notify_all(); 219e4b17023SJohn Marino } 220e4b17023SJohn Marino 221e4b17023SJohn Marino template<typename _Lock> 222e4b17023SJohn Marino void 223e4b17023SJohn Marino wait(_Lock& __lock) 224e4b17023SJohn Marino { 225e4b17023SJohn Marino unique_lock<mutex> __my_lock(_M_mutex); 226e4b17023SJohn Marino _Unlock<_Lock> __unlock(__lock); 227e4b17023SJohn Marino // _M_mutex must be unlocked before re-locking __lock so move 228e4b17023SJohn Marino // ownership of _M_mutex lock to an object with shorter lifetime. 229e4b17023SJohn Marino unique_lock<mutex> __my_lock2(std::move(__my_lock)); 230e4b17023SJohn Marino _M_cond.wait(__my_lock2); 231e4b17023SJohn Marino } 232e4b17023SJohn Marino 233e4b17023SJohn Marino 234e4b17023SJohn Marino template<typename _Lock, typename _Predicate> 235e4b17023SJohn Marino void 236e4b17023SJohn Marino wait(_Lock& __lock, _Predicate __p) 237e4b17023SJohn Marino { 238e4b17023SJohn Marino while (!__p()) 239e4b17023SJohn Marino wait(__lock); 240e4b17023SJohn Marino } 241e4b17023SJohn Marino 242e4b17023SJohn Marino template<typename _Lock, typename _Clock, typename _Duration> 243e4b17023SJohn Marino cv_status 244e4b17023SJohn Marino wait_until(_Lock& __lock, 245e4b17023SJohn Marino const chrono::time_point<_Clock, _Duration>& __atime) 246e4b17023SJohn Marino { 247e4b17023SJohn Marino unique_lock<mutex> __my_lock(_M_mutex); 248e4b17023SJohn Marino _Unlock<_Lock> __unlock(__lock); 249e4b17023SJohn Marino // _M_mutex must be unlocked before re-locking __lock so move 250e4b17023SJohn Marino // ownership of _M_mutex lock to an object with shorter lifetime. 251e4b17023SJohn Marino unique_lock<mutex> __my_lock2(std::move(__my_lock)); 252e4b17023SJohn Marino return _M_cond.wait_until(__my_lock2, __atime); 253e4b17023SJohn Marino } 254e4b17023SJohn Marino 255e4b17023SJohn Marino template<typename _Lock, typename _Clock, 256e4b17023SJohn Marino typename _Duration, typename _Predicate> 257e4b17023SJohn Marino bool 258e4b17023SJohn Marino wait_until(_Lock& __lock, 259e4b17023SJohn Marino const chrono::time_point<_Clock, _Duration>& __atime, 260e4b17023SJohn Marino _Predicate __p) 261e4b17023SJohn Marino { 262e4b17023SJohn Marino while (!__p()) 263e4b17023SJohn Marino if (wait_until(__lock, __atime) == cv_status::timeout) 264e4b17023SJohn Marino return __p(); 265e4b17023SJohn Marino return true; 266e4b17023SJohn Marino } 267e4b17023SJohn Marino 268e4b17023SJohn Marino template<typename _Lock, typename _Rep, typename _Period> 269e4b17023SJohn Marino cv_status 270e4b17023SJohn Marino wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime) 271e4b17023SJohn Marino { return wait_until(__lock, __clock_t::now() + __rtime); } 272e4b17023SJohn Marino 273e4b17023SJohn Marino template<typename _Lock, typename _Rep, 274e4b17023SJohn Marino typename _Period, typename _Predicate> 275e4b17023SJohn Marino bool 276e4b17023SJohn Marino wait_for(_Lock& __lock, 277e4b17023SJohn Marino const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p) 278e4b17023SJohn Marino { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } 279e4b17023SJohn Marino }; 280e4b17023SJohn Marino 281e4b17023SJohn Marino // @} group condition_variables 282e4b17023SJohn Marino_GLIBCXX_END_NAMESPACE_VERSION 283e4b17023SJohn Marino} // namespace 284e4b17023SJohn Marino 285e4b17023SJohn Marino#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 286e4b17023SJohn Marino 287e4b17023SJohn Marino#endif // __GXX_EXPERIMENTAL_CXX0X__ 288e4b17023SJohn Marino 289e4b17023SJohn Marino#endif // _GLIBCXX_CONDITION_VARIABLE 290