libstdc++
atomic_timed_wait.h
Go to the documentation of this file.
1 // -*- C++ -*- header.
2 
3 // Copyright (C) 2020-2026 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 bits/atomic_timed_wait.h
26  * This is an internal header file, included by other library headers.
27  * Do not attempt to use it directly. @headername{atomic}
28  */
29 
30 #ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
31 #define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
32 
33 #ifdef _GLIBCXX_SYSHDR
34 #pragma GCC system_header
35 #endif
36 
37 #include <bits/atomic_wait.h>
38 
39 #if __glibcxx_atomic_wait
40 #include <bits/this_thread_sleep.h>
41 #include <bits/chrono.h>
42 
43 #ifdef _GLIBCXX_HAVE_LINUX_FUTEX
44 #include <sys/time.h>
45 #endif
46 
47 namespace std _GLIBCXX_VISIBILITY(default)
48 {
49 _GLIBCXX_BEGIN_NAMESPACE_VERSION
50 
51  namespace __detail
52  {
53  using __wait_clock_t = chrono::steady_clock;
54 
55  template<typename _Clock, typename _Dur>
56  __wait_clock_t::time_point
57  __to_wait_clock(const chrono::time_point<_Clock, _Dur>& __atime) noexcept
58  {
59  const typename _Clock::time_point __c_entry = _Clock::now();
60  const __wait_clock_t::time_point __w_entry = __wait_clock_t::now();
61  const auto __delta = __atime - __c_entry;
62  using __w_dur = typename __wait_clock_t::duration;
63  return __w_entry + chrono::ceil<__w_dur>(__delta);
64  }
65 
66  template<typename _Dur>
67  __wait_clock_t::time_point
68  __to_wait_clock(const chrono::time_point<__wait_clock_t,
69  _Dur>& __atime) noexcept
70  {
71  using __w_dur = typename __wait_clock_t::duration;
72  if constexpr (is_same_v<__w_dur, _Dur>)
73  return __atime;
74  else
75  return chrono::ceil<__w_dur>(__atime);
76  }
77 
78  // This uses a nanoseconds duration for the timeout argument.
79  // For __abi_version=0 that is the time since the steady_clock's epoch.
80  // It's possible that in future we will add new __wait_flags constants
81  // to indicate that the timeout is the time since the system_clock epoch,
82  // or is a relative timeout not an absolute time.
83  __wait_result_type
84  __wait_until_impl(const void* __addr, __wait_args_base& __args,
85  const chrono::nanoseconds& __timeout);
86 
87  template<typename _Clock, typename _Dur>
88  __wait_result_type
89  __wait_until(const void* __addr, __wait_args_base& __args,
90  const chrono::time_point<_Clock, _Dur>& __atime) noexcept
91  {
92  auto __at = __detail::__to_wait_clock(__atime);
93  auto __res = __detail::__wait_until_impl(__addr, __args,
94  __at.time_since_epoch());
95 
96  if constexpr (!is_same_v<__wait_clock_t, _Clock>)
97  if (__res._M_timeout)
98  {
99  // We got a timeout when measured against __clock_t but
100  // we need to check against the caller-supplied clock
101  // to tell whether we should return a timeout.
102  if (_Clock::now() < __atime)
103  __res._M_timeout = false;
104  }
105  return __res;
106  }
107 
108  template<typename _Rep, typename _Period>
109  __wait_result_type
110  __wait_for(const void* __addr, __wait_args_base& __args,
111  const chrono::duration<_Rep, _Period>& __rtime) noexcept
112  {
113  if (!__rtime.count())
114  {
115  // no rtime supplied, just spin a bit
116  __args._M_flags |= __wait_flags::__do_spin | __wait_flags::__spin_only;
117  return __detail::__wait_impl(__addr, __args);
118  }
119 
120  auto const __reltime = chrono::ceil<__wait_clock_t::duration>(__rtime);
121  auto const __atime = chrono::steady_clock::now() + __reltime;
122  return __detail::__wait_until(__addr, __args, __atime);
123  }
124  } // namespace __detail
125 
126  // returns true if wait ended before timeout
127  template<typename _Tp,
128  typename _Pred, typename _ValFn,
129  typename _Clock, typename _Dur>
130  bool
131  __atomic_wait_address_until(const _Tp* __addr, _Pred&& __pred,
132  _ValFn&& __vfn,
133  const chrono::time_point<_Clock, _Dur>& __atime,
134  bool __bare_wait = false) noexcept
135  {
136  __detail::__wait_args __args{ __addr, __bare_wait };
137  _Tp __val = __args._M_setup_wait(__addr, __vfn);
138  while (!__pred(__val))
139  {
140  auto __res = __detail::__wait_until(__addr, __args, __atime);
141  if (__res._M_timeout)
142  return false; // C++26 will also return last observed __val
143  __val = __args._M_on_wake(__addr, __vfn, __res);
144  }
145  return true; // C++26 will also return last observed __val
146  }
147 
148  template<typename _Clock, typename _Dur>
149  bool
150  __atomic_wait_address_until_v(const __detail::__platform_wait_t* __addr,
151  __detail::__platform_wait_t __old,
152  int __order,
153  const chrono::time_point<_Clock, _Dur>& __atime,
154  bool __bare_wait = false) noexcept
155  {
156  // This function must not be used if __wait_impl might use a proxy wait:
157  __glibcxx_assert(__platform_wait_uses_type<__detail::__platform_wait_t>);
158 
159  __detail::__wait_args __args{ __addr, __old, __order, __bare_wait };
160  auto __res = __detail::__wait_until(__addr, __args, __atime);
161  return !__res._M_timeout; // C++26 will also return last observed __val
162  }
163 
164  template<typename _Tp, typename _ValFn,
165  typename _Clock, typename _Dur>
166  bool
167  __atomic_wait_address_until_v(const _Tp* __addr, _Tp&& __old,
168  _ValFn&& __vfn,
169  const chrono::time_point<_Clock, _Dur>& __atime,
170  bool __bare_wait = false) noexcept
171  {
172  auto __pfn = [&](const _Tp& __val) {
173  return !__detail::__atomic_eq(__old, __val);
174  };
175  return std::__atomic_wait_address_until(__addr, __pfn, __vfn, __atime,
176  __bare_wait);
177  }
178 
179  template<typename _Tp,
180  typename _Pred, typename _ValFn,
181  typename _Rep, typename _Period>
182  bool
183  __atomic_wait_address_for(const _Tp* __addr, _Pred&& __pred,
184  _ValFn&& __vfn,
185  const chrono::duration<_Rep, _Period>& __rtime,
186  bool __bare_wait = false) noexcept
187  {
188  __detail::__wait_args __args{ __addr, __bare_wait };
189  _Tp __val = __args._M_setup_wait(__addr, __vfn);
190  while (!__pred(__val))
191  {
192  auto __res = __detail::__wait_for(__addr, __args, __rtime);
193  if (__res._M_timeout)
194  return false; // C++26 will also return last observed __val
195  __val = __args._M_on_wake(__addr, __vfn, __res);
196  }
197  return true; // C++26 will also return last observed __val
198  }
199 
200  template<typename _Rep, typename _Period>
201  bool
202  __atomic_wait_address_for_v(const __detail::__platform_wait_t* __addr,
203  __detail::__platform_wait_t __old,
204  int __order,
205  const chrono::duration<_Rep, _Period>& __rtime,
206  bool __bare_wait = false) noexcept
207  {
208  // This function must not be used if __wait_impl might use a proxy wait:
209  __glibcxx_assert(__platform_wait_uses_type<__detail::__platform_wait_t>);
210 
211  __detail::__wait_args __args{ __addr, __old, __order, __bare_wait };
212  auto __res = __detail::__wait_for(__addr, __args, __rtime);
213  return !__res._M_timeout; // C++26 will also return last observed __val
214  }
215 
216  template<typename _Tp, typename _ValFn,
217  typename _Rep, typename _Period>
218  bool
219  __atomic_wait_address_for_v(const _Tp* __addr, _Tp&& __old, _ValFn&& __vfn,
220  const chrono::duration<_Rep, _Period>& __rtime,
221  bool __bare_wait = false) noexcept
222  {
223  auto __pfn = [&](const _Tp& __val) {
224  return !__detail::__atomic_eq(__old, __val);
225  };
226  return __atomic_wait_address_for(__addr, __pfn, forward<_ValFn>(__vfn),
227  __rtime, __bare_wait);
228  }
229 _GLIBCXX_END_NAMESPACE_VERSION
230 } // namespace std
231 #endif // __cpp_lib_atomic_wait
232 #endif // _GLIBCXX_ATOMIC_TIMED_WAIT_H
duration< int64_t, nano > nanoseconds
nanoseconds
Definition: chrono.h:892
ISO C++ entities toplevel namespace is std.
Definition: simd.h:306