1// <condition_variable> -*- C++ -*- 2 3// Copyright (C) 2008-2020 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 40#include <bits/std_mutex.h> 41#include <bits/unique_lock.h> 42#include <ext/concurrence.h> 43#include <bits/alloc_traits.h> 44#include <bits/allocator.h> 45#include <bits/unique_ptr.h> 46#include <bits/shared_ptr.h> 47#include <bits/cxxabi_forced.h> 48 49#if __cplusplus > 201703L 50# include <stop_token> 51#endif 52 53#if defined(_GLIBCXX_HAS_GTHREADS) 54 55namespace std _GLIBCXX_VISIBILITY(default) 56{ 57_GLIBCXX_BEGIN_NAMESPACE_VERSION 58 59 /** 60 * @defgroup condition_variables Condition Variables 61 * @ingroup concurrency 62 * 63 * Classes for condition_variable support. 64 * @{ 65 */ 66 67 /// cv_status 68 enum class cv_status { no_timeout, timeout }; 69 70 /// condition_variable 71 class condition_variable 72 { 73 using steady_clock = chrono::steady_clock; 74 using system_clock = chrono::system_clock; 75#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT 76 using __clock_t = steady_clock; 77#else 78 using __clock_t = system_clock; 79#endif 80 typedef __gthread_cond_t __native_type; 81 82#ifdef __GTHREAD_COND_INIT 83 __native_type _M_cond = __GTHREAD_COND_INIT; 84#else 85 __native_type _M_cond; 86#endif 87 88 public: 89 typedef __native_type* native_handle_type; 90 91 condition_variable() noexcept; 92 ~condition_variable() noexcept; 93 94 condition_variable(const condition_variable&) = delete; 95 condition_variable& operator=(const condition_variable&) = delete; 96 97 void 98 notify_one() noexcept; 99 100 void 101 notify_all() noexcept; 102 103 void 104 wait(unique_lock<mutex>& __lock) noexcept; 105 106 template<typename _Predicate> 107 void 108 wait(unique_lock<mutex>& __lock, _Predicate __p) 109 { 110 while (!__p()) 111 wait(__lock); 112 } 113 114#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT 115 template<typename _Duration> 116 cv_status 117 wait_until(unique_lock<mutex>& __lock, 118 const chrono::time_point<steady_clock, _Duration>& __atime) 119 { return __wait_until_impl(__lock, __atime); } 120#endif 121 122 template<typename _Duration> 123 cv_status 124 wait_until(unique_lock<mutex>& __lock, 125 const chrono::time_point<system_clock, _Duration>& __atime) 126 { return __wait_until_impl(__lock, __atime); } 127 128 template<typename _Clock, typename _Duration> 129 cv_status 130 wait_until(unique_lock<mutex>& __lock, 131 const chrono::time_point<_Clock, _Duration>& __atime) 132 { 133#if __cplusplus > 201703L 134 static_assert(chrono::is_clock_v<_Clock>); 135#endif 136 const typename _Clock::time_point __c_entry = _Clock::now(); 137 const __clock_t::time_point __s_entry = __clock_t::now(); 138 const auto __delta = __atime - __c_entry; 139 const auto __s_atime = __s_entry + __delta; 140 141 if (__wait_until_impl(__lock, __s_atime) == cv_status::no_timeout) 142 return cv_status::no_timeout; 143 // We got a timeout when measured against __clock_t but 144 // we need to check against the caller-supplied clock 145 // to tell whether we should return a timeout. 146 if (_Clock::now() < __atime) 147 return cv_status::no_timeout; 148 return cv_status::timeout; 149 } 150 151 template<typename _Clock, typename _Duration, typename _Predicate> 152 bool 153 wait_until(unique_lock<mutex>& __lock, 154 const chrono::time_point<_Clock, _Duration>& __atime, 155 _Predicate __p) 156 { 157 while (!__p()) 158 if (wait_until(__lock, __atime) == cv_status::timeout) 159 return __p(); 160 return true; 161 } 162 163 template<typename _Rep, typename _Period> 164 cv_status 165 wait_for(unique_lock<mutex>& __lock, 166 const chrono::duration<_Rep, _Period>& __rtime) 167 { 168 using __dur = typename steady_clock::duration; 169 auto __reltime = chrono::duration_cast<__dur>(__rtime); 170 if (__reltime < __rtime) 171 ++__reltime; 172 return wait_until(__lock, steady_clock::now() + __reltime); 173 } 174 175 template<typename _Rep, typename _Period, typename _Predicate> 176 bool 177 wait_for(unique_lock<mutex>& __lock, 178 const chrono::duration<_Rep, _Period>& __rtime, 179 _Predicate __p) 180 { 181 using __dur = typename steady_clock::duration; 182 auto __reltime = chrono::duration_cast<__dur>(__rtime); 183 if (__reltime < __rtime) 184 ++__reltime; 185 return wait_until(__lock, steady_clock::now() + __reltime, 186 std::move(__p)); 187 } 188 189 native_handle_type 190 native_handle() 191 { return &_M_cond; } 192 193 private: 194#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT 195 template<typename _Dur> 196 cv_status 197 __wait_until_impl(unique_lock<mutex>& __lock, 198 const chrono::time_point<steady_clock, _Dur>& __atime) 199 { 200 auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 201 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 202 203 __gthread_time_t __ts = 204 { 205 static_cast<std::time_t>(__s.time_since_epoch().count()), 206 static_cast<long>(__ns.count()) 207 }; 208 209 pthread_cond_clockwait(&_M_cond, __lock.mutex()->native_handle(), 210 CLOCK_MONOTONIC, 211 &__ts); 212 213 return (steady_clock::now() < __atime 214 ? cv_status::no_timeout : cv_status::timeout); 215 } 216#endif 217 218 template<typename _Dur> 219 cv_status 220 __wait_until_impl(unique_lock<mutex>& __lock, 221 const chrono::time_point<system_clock, _Dur>& __atime) 222 { 223 auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 224 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 225 226 __gthread_time_t __ts = 227 { 228 static_cast<std::time_t>(__s.time_since_epoch().count()), 229 static_cast<long>(__ns.count()) 230 }; 231 232 __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(), 233 &__ts); 234 235 return (system_clock::now() < __atime 236 ? cv_status::no_timeout : cv_status::timeout); 237 } 238 }; 239 240 void 241 notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>); 242 243 struct __at_thread_exit_elt 244 { 245 __at_thread_exit_elt* _M_next; 246 void (*_M_cb)(void*); 247 }; 248 249 inline namespace _V2 { 250 251 /// condition_variable_any 252 // Like above, but mutex is not required to have try_lock. 253 class condition_variable_any 254 { 255#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT 256 using __clock_t = chrono::steady_clock; 257#else 258 using __clock_t = chrono::system_clock; 259#endif 260 condition_variable _M_cond; 261 shared_ptr<mutex> _M_mutex; 262 263 // scoped unlock - unlocks in ctor, re-locks in dtor 264 template<typename _Lock> 265 struct _Unlock 266 { 267 explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); } 268 269#pragma GCC diagnostic push 270#pragma GCC diagnostic ignored "-Wdeprecated-declarations" 271 ~_Unlock() noexcept(false) 272 { 273 if (uncaught_exception()) 274 { 275 __try 276 { _M_lock.lock(); } 277 __catch(const __cxxabiv1::__forced_unwind&) 278 { __throw_exception_again; } 279 __catch(...) 280 { } 281 } 282 else 283 _M_lock.lock(); 284 } 285#pragma GCC diagnostic pop 286 287 _Unlock(const _Unlock&) = delete; 288 _Unlock& operator=(const _Unlock&) = delete; 289 290 _Lock& _M_lock; 291 }; 292 293 public: 294 condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { } 295 ~condition_variable_any() = default; 296 297 condition_variable_any(const condition_variable_any&) = delete; 298 condition_variable_any& operator=(const condition_variable_any&) = delete; 299 300 void 301 notify_one() noexcept 302 { 303 lock_guard<mutex> __lock(*_M_mutex); 304 _M_cond.notify_one(); 305 } 306 307 void 308 notify_all() noexcept 309 { 310 lock_guard<mutex> __lock(*_M_mutex); 311 _M_cond.notify_all(); 312 } 313 314 template<typename _Lock> 315 void 316 wait(_Lock& __lock) 317 { 318 shared_ptr<mutex> __mutex = _M_mutex; 319 unique_lock<mutex> __my_lock(*__mutex); 320 _Unlock<_Lock> __unlock(__lock); 321 // *__mutex must be unlocked before re-locking __lock so move 322 // ownership of *__mutex lock to an object with shorter lifetime. 323 unique_lock<mutex> __my_lock2(std::move(__my_lock)); 324 _M_cond.wait(__my_lock2); 325 } 326 327 328 template<typename _Lock, typename _Predicate> 329 void 330 wait(_Lock& __lock, _Predicate __p) 331 { 332 while (!__p()) 333 wait(__lock); 334 } 335 336 template<typename _Lock, typename _Clock, typename _Duration> 337 cv_status 338 wait_until(_Lock& __lock, 339 const chrono::time_point<_Clock, _Duration>& __atime) 340 { 341 shared_ptr<mutex> __mutex = _M_mutex; 342 unique_lock<mutex> __my_lock(*__mutex); 343 _Unlock<_Lock> __unlock(__lock); 344 // *__mutex must be unlocked before re-locking __lock so move 345 // ownership of *__mutex lock to an object with shorter lifetime. 346 unique_lock<mutex> __my_lock2(std::move(__my_lock)); 347 return _M_cond.wait_until(__my_lock2, __atime); 348 } 349 350 template<typename _Lock, typename _Clock, 351 typename _Duration, typename _Predicate> 352 bool 353 wait_until(_Lock& __lock, 354 const chrono::time_point<_Clock, _Duration>& __atime, 355 _Predicate __p) 356 { 357 while (!__p()) 358 if (wait_until(__lock, __atime) == cv_status::timeout) 359 return __p(); 360 return true; 361 } 362 363 template<typename _Lock, typename _Rep, typename _Period> 364 cv_status 365 wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime) 366 { return wait_until(__lock, __clock_t::now() + __rtime); } 367 368 template<typename _Lock, typename _Rep, 369 typename _Period, typename _Predicate> 370 bool 371 wait_for(_Lock& __lock, 372 const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p) 373 { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } 374 375#ifdef __cpp_lib_jthread 376 template <class _Lock, class _Predicate> 377 bool wait(_Lock& __lock, 378 stop_token __stoken, 379 _Predicate __p) 380 { 381 if (__stoken.stop_requested()) 382 { 383 return __p(); 384 } 385 386 std::stop_callback __cb(__stoken, [this] { notify_all(); }); 387 shared_ptr<mutex> __mutex = _M_mutex; 388 while (!__p()) 389 { 390 unique_lock<mutex> __my_lock(*__mutex); 391 if (__stoken.stop_requested()) 392 { 393 return false; 394 } 395 // *__mutex must be unlocked before re-locking __lock so move 396 // ownership of *__mutex lock to an object with shorter lifetime. 397 _Unlock<_Lock> __unlock(__lock); 398 unique_lock<mutex> __my_lock2(std::move(__my_lock)); 399 _M_cond.wait(__my_lock2); 400 } 401 return true; 402 } 403 404 template <class _Lock, class _Clock, class _Duration, class _Predicate> 405 bool wait_until(_Lock& __lock, 406 stop_token __stoken, 407 const chrono::time_point<_Clock, _Duration>& __abs_time, 408 _Predicate __p) 409 { 410 if (__stoken.stop_requested()) 411 { 412 return __p(); 413 } 414 415 std::stop_callback __cb(__stoken, [this] { notify_all(); }); 416 shared_ptr<mutex> __mutex = _M_mutex; 417 while (!__p()) 418 { 419 bool __stop; 420 { 421 unique_lock<mutex> __my_lock(*__mutex); 422 if (__stoken.stop_requested()) 423 { 424 return false; 425 } 426 _Unlock<_Lock> __u(__lock); 427 unique_lock<mutex> __my_lock2(std::move(__my_lock)); 428 const auto __status = _M_cond.wait_until(__my_lock2, __abs_time); 429 __stop = (__status == std::cv_status::timeout) || __stoken.stop_requested(); 430 } 431 if (__stop) 432 { 433 return __p(); 434 } 435 } 436 return true; 437 } 438 439 template <class _Lock, class _Rep, class _Period, class _Predicate> 440 bool wait_for(_Lock& __lock, 441 stop_token __stoken, 442 const chrono::duration<_Rep, _Period>& __rel_time, 443 _Predicate __p) 444 { 445 auto __abst = std::chrono::steady_clock::now() + __rel_time; 446 return wait_until(__lock, 447 std::move(__stoken), 448 __abst, 449 std::move(__p)); 450 } 451#endif 452 }; 453 454 } // end inline namespace 455 456 /// @} group condition_variables 457_GLIBCXX_END_NAMESPACE_VERSION 458} // namespace 459 460#endif // _GLIBCXX_HAS_GTHREADS 461#endif // C++11 462#endif // _GLIBCXX_CONDITION_VARIABLE 463