1// <condition_variable> -*- C++ -*- 2 3// Copyright (C) 2008-2014 Free Software Foundation, Inc. 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 8// Free Software Foundation; either version 3, or (at your option) 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 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. 19 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/>. 24 25/** @file include/condition_variable 26 * This is a Standard C++ Library header. 27 */ 28 29#ifndef _GLIBCXX_CONDITION_VARIABLE 30#define _GLIBCXX_CONDITION_VARIABLE 1 31 32#pragma GCC system_header 33 34#if __cplusplus < 201103L 35# include <bits/c++0x_warning.h> 36#else 37 38#include <chrono> 39#include <mutex> 40#include <ext/concurrence.h> 41#include <bits/alloc_traits.h> 42#include <bits/allocator.h> 43#include <bits/unique_ptr.h> 44#include <bits/shared_ptr.h> 45 46#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) 47 48namespace std _GLIBCXX_VISIBILITY(default) 49{ 50_GLIBCXX_BEGIN_NAMESPACE_VERSION 51 52 /** 53 * @defgroup condition_variables Condition Variables 54 * @ingroup concurrency 55 * 56 * Classes for condition_variable support. 57 * @{ 58 */ 59 60 /// cv_status 61 enum class cv_status { no_timeout, timeout }; 62 63 /// condition_variable 64 class condition_variable 65 { 66 typedef chrono::system_clock __clock_t; 67 typedef __gthread_cond_t __native_type; 68 69#ifdef __GTHREAD_COND_INIT 70 __native_type _M_cond = __GTHREAD_COND_INIT; 71#else 72 __native_type _M_cond; 73#endif 74 75 public: 76 typedef __native_type* native_handle_type; 77 78 condition_variable() noexcept; 79 ~condition_variable() noexcept; 80 81 condition_variable(const condition_variable&) = delete; 82 condition_variable& operator=(const condition_variable&) = delete; 83 84 void 85 notify_one() noexcept; 86 87 void 88 notify_all() noexcept; 89 90 void 91 wait(unique_lock<mutex>& __lock); 92 93 template<typename _Predicate> 94 void 95 wait(unique_lock<mutex>& __lock, _Predicate __p) 96 { 97 while (!__p()) 98 wait(__lock); 99 } 100 101 template<typename _Duration> 102 cv_status 103 wait_until(unique_lock<mutex>& __lock, 104 const chrono::time_point<__clock_t, _Duration>& __atime) 105 { return __wait_until_impl(__lock, __atime); } 106 107 template<typename _Clock, typename _Duration> 108 cv_status 109 wait_until(unique_lock<mutex>& __lock, 110 const chrono::time_point<_Clock, _Duration>& __atime) 111 { 112 // DR 887 - Sync unknown clock to known clock. 113 const typename _Clock::time_point __c_entry = _Clock::now(); 114 const __clock_t::time_point __s_entry = __clock_t::now(); 115 const auto __delta = __atime - __c_entry; 116 const auto __s_atime = __s_entry + __delta; 117 118 return __wait_until_impl(__lock, __s_atime); 119 } 120 121 template<typename _Clock, typename _Duration, typename _Predicate> 122 bool 123 wait_until(unique_lock<mutex>& __lock, 124 const chrono::time_point<_Clock, _Duration>& __atime, 125 _Predicate __p) 126 { 127 while (!__p()) 128 if (wait_until(__lock, __atime) == cv_status::timeout) 129 return __p(); 130 return true; 131 } 132 133 template<typename _Rep, typename _Period> 134 cv_status 135 wait_for(unique_lock<mutex>& __lock, 136 const chrono::duration<_Rep, _Period>& __rtime) 137 { return wait_until(__lock, __clock_t::now() + __rtime); } 138 139 template<typename _Rep, typename _Period, typename _Predicate> 140 bool 141 wait_for(unique_lock<mutex>& __lock, 142 const chrono::duration<_Rep, _Period>& __rtime, 143 _Predicate __p) 144 { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } 145 146 native_handle_type 147 native_handle() 148 { return &_M_cond; } 149 150 private: 151 template<typename _Dur> 152 cv_status 153 __wait_until_impl(unique_lock<mutex>& __lock, 154 const chrono::time_point<__clock_t, _Dur>& __atime) 155 { 156 auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 157 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 158 159 __gthread_time_t __ts = 160 { 161 static_cast<std::time_t>(__s.time_since_epoch().count()), 162 static_cast<long>(__ns.count()) 163 }; 164 165 __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(), 166 &__ts); 167 168 return (__clock_t::now() < __atime 169 ? cv_status::no_timeout : cv_status::timeout); 170 } 171 }; 172 173 inline namespace _V2 { 174 175 /// condition_variable_any 176 // Like above, but mutex is not required to have try_lock. 177 class condition_variable_any 178 { 179 typedef chrono::system_clock __clock_t; 180 condition_variable _M_cond; 181 shared_ptr<mutex> _M_mutex; 182 183 // scoped unlock - unlocks in ctor, re-locks in dtor 184 template<typename _Lock> 185 struct _Unlock 186 { 187 explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); } 188 189 ~_Unlock() noexcept(false) 190 { 191 if (uncaught_exception()) 192 { 193 __try 194 { _M_lock.lock(); } 195 __catch(const __cxxabiv1::__forced_unwind&) 196 { __throw_exception_again; } 197 __catch(...) 198 { } 199 } 200 else 201 _M_lock.lock(); 202 } 203 204 _Unlock(const _Unlock&) = delete; 205 _Unlock& operator=(const _Unlock&) = delete; 206 207 _Lock& _M_lock; 208 }; 209 210 public: 211 condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { } 212 ~condition_variable_any() = default; 213 214 condition_variable_any(const condition_variable_any&) = delete; 215 condition_variable_any& operator=(const condition_variable_any&) = delete; 216 217 void 218 notify_one() noexcept 219 { 220 lock_guard<mutex> __lock(*_M_mutex); 221 _M_cond.notify_one(); 222 } 223 224 void 225 notify_all() noexcept 226 { 227 lock_guard<mutex> __lock(*_M_mutex); 228 _M_cond.notify_all(); 229 } 230 231 template<typename _Lock> 232 void 233 wait(_Lock& __lock) 234 { 235 shared_ptr<mutex> __mutex = _M_mutex; 236 unique_lock<mutex> __my_lock(*__mutex); 237 _Unlock<_Lock> __unlock(__lock); 238 // *__mutex must be unlocked before re-locking __lock so move 239 // ownership of *__mutex lock to an object with shorter lifetime. 240 unique_lock<mutex> __my_lock2(std::move(__my_lock)); 241 _M_cond.wait(__my_lock2); 242 } 243 244 245 template<typename _Lock, typename _Predicate> 246 void 247 wait(_Lock& __lock, _Predicate __p) 248 { 249 while (!__p()) 250 wait(__lock); 251 } 252 253 template<typename _Lock, typename _Clock, typename _Duration> 254 cv_status 255 wait_until(_Lock& __lock, 256 const chrono::time_point<_Clock, _Duration>& __atime) 257 { 258 shared_ptr<mutex> __mutex = _M_mutex; 259 unique_lock<mutex> __my_lock(*__mutex); 260 _Unlock<_Lock> __unlock(__lock); 261 // *__mutex must be unlocked before re-locking __lock so move 262 // ownership of *__mutex lock to an object with shorter lifetime. 263 unique_lock<mutex> __my_lock2(std::move(__my_lock)); 264 return _M_cond.wait_until(__my_lock2, __atime); 265 } 266 267 template<typename _Lock, typename _Clock, 268 typename _Duration, typename _Predicate> 269 bool 270 wait_until(_Lock& __lock, 271 const chrono::time_point<_Clock, _Duration>& __atime, 272 _Predicate __p) 273 { 274 while (!__p()) 275 if (wait_until(__lock, __atime) == cv_status::timeout) 276 return __p(); 277 return true; 278 } 279 280 template<typename _Lock, typename _Rep, typename _Period> 281 cv_status 282 wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime) 283 { return wait_until(__lock, __clock_t::now() + __rtime); } 284 285 template<typename _Lock, typename _Rep, 286 typename _Period, typename _Predicate> 287 bool 288 wait_for(_Lock& __lock, 289 const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p) 290 { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } 291 }; 292 293 } // end inline namespace 294 295 // @} group condition_variables 296_GLIBCXX_END_NAMESPACE_VERSION 297} // namespace 298 299#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 300 301#endif // C++11 302 303#endif // _GLIBCXX_CONDITION_VARIABLE 304