1// <condition_variable> -*- C++ -*- 2 3// Copyright (C) 2008-2015 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 void 174 notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>); 175 176 struct __at_thread_exit_elt 177 { 178 __at_thread_exit_elt* _M_next; 179 void (*_M_cb)(void*); 180 }; 181 182 inline namespace _V2 { 183 184 /// condition_variable_any 185 // Like above, but mutex is not required to have try_lock. 186 class condition_variable_any 187 { 188 typedef chrono::system_clock __clock_t; 189 condition_variable _M_cond; 190 shared_ptr<mutex> _M_mutex; 191 192 // scoped unlock - unlocks in ctor, re-locks in dtor 193 template<typename _Lock> 194 struct _Unlock 195 { 196 explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); } 197 198 ~_Unlock() noexcept(false) 199 { 200 if (uncaught_exception()) 201 { 202 __try 203 { _M_lock.lock(); } 204 __catch(const __cxxabiv1::__forced_unwind&) 205 { __throw_exception_again; } 206 __catch(...) 207 { } 208 } 209 else 210 _M_lock.lock(); 211 } 212 213 _Unlock(const _Unlock&) = delete; 214 _Unlock& operator=(const _Unlock&) = delete; 215 216 _Lock& _M_lock; 217 }; 218 219 public: 220 condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { } 221 ~condition_variable_any() = default; 222 223 condition_variable_any(const condition_variable_any&) = delete; 224 condition_variable_any& operator=(const condition_variable_any&) = delete; 225 226 void 227 notify_one() noexcept 228 { 229 lock_guard<mutex> __lock(*_M_mutex); 230 _M_cond.notify_one(); 231 } 232 233 void 234 notify_all() noexcept 235 { 236 lock_guard<mutex> __lock(*_M_mutex); 237 _M_cond.notify_all(); 238 } 239 240 template<typename _Lock> 241 void 242 wait(_Lock& __lock) 243 { 244 shared_ptr<mutex> __mutex = _M_mutex; 245 unique_lock<mutex> __my_lock(*__mutex); 246 _Unlock<_Lock> __unlock(__lock); 247 // *__mutex must be unlocked before re-locking __lock so move 248 // ownership of *__mutex lock to an object with shorter lifetime. 249 unique_lock<mutex> __my_lock2(std::move(__my_lock)); 250 _M_cond.wait(__my_lock2); 251 } 252 253 254 template<typename _Lock, typename _Predicate> 255 void 256 wait(_Lock& __lock, _Predicate __p) 257 { 258 while (!__p()) 259 wait(__lock); 260 } 261 262 template<typename _Lock, typename _Clock, typename _Duration> 263 cv_status 264 wait_until(_Lock& __lock, 265 const chrono::time_point<_Clock, _Duration>& __atime) 266 { 267 shared_ptr<mutex> __mutex = _M_mutex; 268 unique_lock<mutex> __my_lock(*__mutex); 269 _Unlock<_Lock> __unlock(__lock); 270 // *__mutex must be unlocked before re-locking __lock so move 271 // ownership of *__mutex lock to an object with shorter lifetime. 272 unique_lock<mutex> __my_lock2(std::move(__my_lock)); 273 return _M_cond.wait_until(__my_lock2, __atime); 274 } 275 276 template<typename _Lock, typename _Clock, 277 typename _Duration, typename _Predicate> 278 bool 279 wait_until(_Lock& __lock, 280 const chrono::time_point<_Clock, _Duration>& __atime, 281 _Predicate __p) 282 { 283 while (!__p()) 284 if (wait_until(__lock, __atime) == cv_status::timeout) 285 return __p(); 286 return true; 287 } 288 289 template<typename _Lock, typename _Rep, typename _Period> 290 cv_status 291 wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime) 292 { return wait_until(__lock, __clock_t::now() + __rtime); } 293 294 template<typename _Lock, typename _Rep, 295 typename _Period, typename _Predicate> 296 bool 297 wait_for(_Lock& __lock, 298 const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p) 299 { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } 300 }; 301 302 } // end inline namespace 303 304 // @} group condition_variables 305_GLIBCXX_END_NAMESPACE_VERSION 306} // namespace 307 308#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 309 310#endif // C++11 311 312#endif // _GLIBCXX_CONDITION_VARIABLE 313