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