1// <condition_variable> -*- C++ -*- 2 3// Copyright (C) 2008, 2009, 2010 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 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#ifndef __GXX_EXPERIMENTAL_CXX0X__ 35# include <bits/c++0x_warning.h> 36#else 37 38#include <chrono> 39#include <mutex> // unique_lock 40 41#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) 42 43namespace std 44{ 45 /** 46 * @defgroup condition_variables Condition Variables 47 * @ingroup concurrency 48 * 49 * Classes for condition_variable support. 50 * @{ 51 */ 52 53 /// cv_status 54 enum class cv_status { no_timeout, timeout }; 55 56 /// condition_variable 57 class condition_variable 58 { 59 typedef chrono::system_clock __clock_t; 60 typedef __gthread_cond_t __native_type; 61 __native_type _M_cond; 62 63 public: 64 typedef __native_type* native_handle_type; 65 66 condition_variable() throw (); 67 ~condition_variable() throw (); 68 69 condition_variable(const condition_variable&) = delete; 70 condition_variable& operator=(const condition_variable&) = delete; 71 72 void 73 notify_one(); 74 75 void 76 notify_all(); 77 78 void 79 wait(unique_lock<mutex>& __lock); 80 81 template<typename _Predicate> 82 void 83 wait(unique_lock<mutex>& __lock, _Predicate __p) 84 { 85 while (!__p()) 86 wait(__lock); 87 } 88 89 template<typename _Duration> 90 cv_status 91 wait_until(unique_lock<mutex>& __lock, 92 const chrono::time_point<__clock_t, _Duration>& __atime) 93 { return __wait_until_impl(__lock, __atime); } 94 95 template<typename _Clock, typename _Duration> 96 cv_status 97 wait_until(unique_lock<mutex>& __lock, 98 const chrono::time_point<_Clock, _Duration>& __atime) 99 { 100 // DR 887 - Sync unknown clock to known clock. 101 const typename _Clock::time_point __c_entry = _Clock::now(); 102 const __clock_t::time_point __s_entry = __clock_t::now(); 103 const chrono::nanoseconds __delta = __atime - __c_entry; 104 const __clock_t::time_point __s_atime = __s_entry + __delta; 105 106 return __wait_until_impl(__lock, __s_atime); 107 } 108 109 template<typename _Clock, typename _Duration, typename _Predicate> 110 bool 111 wait_until(unique_lock<mutex>& __lock, 112 const chrono::time_point<_Clock, _Duration>& __atime, 113 _Predicate __p) 114 { 115 while (!__p()) 116 if (wait_until(__lock, __atime) == cv_status::timeout) 117 return __p(); 118 return true; 119 } 120 121 template<typename _Rep, typename _Period> 122 cv_status 123 wait_for(unique_lock<mutex>& __lock, 124 const chrono::duration<_Rep, _Period>& __rtime) 125 { return wait_until(__lock, __clock_t::now() + __rtime); } 126 127 template<typename _Rep, typename _Period, typename _Predicate> 128 bool 129 wait_for(unique_lock<mutex>& __lock, 130 const chrono::duration<_Rep, _Period>& __rtime, 131 _Predicate __p) 132 { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } 133 134 native_handle_type 135 native_handle() 136 { return &_M_cond; } 137 138 private: 139 template<typename _Clock, typename _Duration> 140 cv_status 141 __wait_until_impl(unique_lock<mutex>& __lock, 142 const chrono::time_point<_Clock, _Duration>& __atime) 143 { 144 chrono::time_point<__clock_t, chrono::seconds> __s = 145 chrono::time_point_cast<chrono::seconds>(__atime); 146 147 chrono::nanoseconds __ns = 148 chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 149 150 __gthread_time_t __ts = 151 { 152 static_cast<std::time_t>(__s.time_since_epoch().count()), 153 static_cast<long>(__ns.count()) 154 }; 155 156 __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(), 157 &__ts); 158 159 return (_Clock::now() < __atime 160 ? cv_status::no_timeout : cv_status::timeout); 161 } 162 }; 163 164 /// condition_variable_any 165 // Like above, but mutex is not required to have try_lock. 166 class condition_variable_any 167 { 168 typedef chrono::system_clock __clock_t; 169 condition_variable _M_cond; 170 mutex _M_mutex; 171 172 public: 173 typedef condition_variable::native_handle_type native_handle_type; 174 175 condition_variable_any() throw (); 176 ~condition_variable_any() throw (); 177 178 condition_variable_any(const condition_variable_any&) = delete; 179 condition_variable_any& operator=(const condition_variable_any&) = delete; 180 181 void 182 notify_one() 183 { 184 lock_guard<mutex> __lock(_M_mutex); 185 _M_cond.notify_one(); 186 } 187 188 void 189 notify_all() 190 { 191 lock_guard<mutex> __lock(_M_mutex); 192 _M_cond.notify_all(); 193 } 194 195 template<typename _Lock> 196 void 197 wait(_Lock& __lock) 198 { 199 unique_lock<mutex> __my_lock(_M_mutex); 200 __lock.unlock(); 201 _M_cond.wait(__my_lock); 202 __lock.lock(); 203 } 204 205 206 template<typename _Lock, typename _Predicate> 207 void 208 wait(_Lock& __lock, _Predicate __p) 209 { 210 while (!__p()) 211 wait(__lock); 212 } 213 214 template<typename _Lock, typename _Clock, typename _Duration> 215 cv_status 216 wait_until(_Lock& __lock, 217 const chrono::time_point<_Clock, _Duration>& __atime) 218 { 219 unique_lock<mutex> __my_lock(_M_mutex); 220 __lock.unlock(); 221 cv_status __status = _M_cond.wait_until(__my_lock, __atime); 222 __lock.lock(); 223 return __status; 224 } 225 226 template<typename _Lock, typename _Clock, 227 typename _Duration, typename _Predicate> 228 bool 229 wait_until(_Lock& __lock, 230 const chrono::time_point<_Clock, _Duration>& __atime, 231 _Predicate __p) 232 { 233 while (!__p()) 234 if (wait_until(__lock, __atime) == cv_status::timeout) 235 return __p(); 236 return true; 237 } 238 239 template<typename _Lock, typename _Rep, typename _Period> 240 cv_status 241 wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime) 242 { return wait_until(__lock, __clock_t::now() + __rtime); } 243 244 template<typename _Lock, typename _Rep, 245 typename _Period, typename _Predicate> 246 bool 247 wait_for(_Lock& __lock, 248 const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p) 249 { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } 250 251 native_handle_type 252 native_handle() 253 { return _M_cond.native_handle(); } 254 }; 255 256 // @} group condition_variables 257} 258 259#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 260 261#endif // __GXX_EXPERIMENTAL_CXX0X__ 262 263#endif // _GLIBCXX_CONDITION_VARIABLE 264