30 #ifndef _GLIBCXX_ATOMIC_FUTEX_H
31 #define _GLIBCXX_ATOMIC_FUTEX_H 1
33 #pragma GCC system_header
38 #if ! (defined(_GLIBCXX_HAVE_LINUX_FUTEX) && ATOMIC_INT_LOCK_FREE > 1)
40 #include <condition_variable>
43 #ifndef _GLIBCXX_ALWAYS_INLINE
44 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
47 namespace std _GLIBCXX_VISIBILITY(default)
49 _GLIBCXX_BEGIN_NAMESPACE_VERSION
51 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
52 #if defined(_GLIBCXX_HAVE_LINUX_FUTEX) && ATOMIC_INT_LOCK_FREE > 1
53 struct __atomic_futex_unsigned_base
57 _M_futex_wait_until(
unsigned *__addr,
unsigned __val,
bool __has_timeout,
58 chrono::seconds __s, chrono::nanoseconds __ns);
61 static void _M_futex_notify_all(
unsigned* __addr);
64 template <
unsigned _Waiter_bit = 0x80000000>
65 class __atomic_futex_unsigned : __atomic_futex_unsigned_base
67 typedef chrono::system_clock __clock_t;
70 atomic<unsigned> _M_data;
74 __atomic_futex_unsigned(
unsigned __data) : _M_data(__data)
77 _GLIBCXX_ALWAYS_INLINE
unsigned
80 return _M_data.load(__mo) & ~_Waiter_bit;
90 _M_load_and_test_until(
unsigned __assumed,
unsigned __operand,
92 chrono::seconds __s, chrono::nanoseconds __ns)
101 _M_data.fetch_or(_Waiter_bit, memory_order_relaxed);
103 __ret = _M_futex_wait_until((
unsigned*)(
void*)&_M_data,
104 __assumed | _Waiter_bit, __has_timeout, __s, __ns);
106 __assumed = _M_load(__mo);
107 if (!__ret || ((__operand == __assumed) == __equal))
118 _M_load_and_test(
unsigned __assumed,
unsigned __operand,
121 return _M_load_and_test_until(__assumed, __operand, __equal, __mo,
122 false, chrono::seconds(0), chrono::nanoseconds(0));
130 template<
typename _Dur>
132 _M_load_and_test_until_impl(
unsigned __assumed,
unsigned __operand,
134 const chrono::time_point<__clock_t, _Dur>& __atime)
136 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
137 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
139 return _M_load_and_test_until(__assumed, __operand, __equal, __mo,
140 true, __s.time_since_epoch(), __ns);
145 _GLIBCXX_ALWAYS_INLINE
unsigned
146 _M_load_when_not_equal(
unsigned __val,
memory_order __mo)
148 unsigned __i = _M_load(__mo);
149 if ((__i & ~_Waiter_bit) != __val)
return;
151 return _M_load_and_test(__i, __val,
false, __mo);
154 _GLIBCXX_ALWAYS_INLINE
void
157 unsigned __i = _M_load(__mo);
158 if ((__i & ~_Waiter_bit) == __val)
161 _M_load_and_test(__i, __val,
true, __mo);
165 template<
typename _Rep,
typename _Period>
166 _GLIBCXX_ALWAYS_INLINE
bool
167 _M_load_when_equal_for(
unsigned __val,
memory_order __mo,
168 const chrono::duration<_Rep, _Period>& __rtime)
170 return _M_load_when_equal_until(__val, __mo,
171 __clock_t::now() + __rtime);
175 template<
typename _Clock,
typename _Duration>
176 _GLIBCXX_ALWAYS_INLINE
bool
177 _M_load_when_equal_until(
unsigned __val,
memory_order __mo,
178 const chrono::time_point<_Clock, _Duration>& __atime)
181 const typename _Clock::time_point __c_entry = _Clock::now();
182 const __clock_t::time_point __s_entry = __clock_t::now();
183 const auto __delta = __atime - __c_entry;
184 const auto __s_atime = __s_entry + __delta;
185 return _M_load_when_equal_until(__val, __mo, __s_atime);
189 template<
typename _Duration>
190 _GLIBCXX_ALWAYS_INLINE
bool
191 _M_load_when_equal_until(
unsigned __val,
memory_order __mo,
192 const chrono::time_point<__clock_t, _Duration>& __atime)
194 unsigned __i = _M_load(__mo);
195 if ((__i & ~_Waiter_bit) == __val)
198 __i = _M_load_and_test_until_impl(__i, __val,
true, __mo, __atime);
199 return (__i & ~_Waiter_bit) == __val;
202 _GLIBCXX_ALWAYS_INLINE
void
205 unsigned* __futex = (
unsigned *)(
void *)&_M_data;
206 if (_M_data.exchange(__val, __mo) & _Waiter_bit)
207 _M_futex_notify_all(__futex);
211 #else // ! (_GLIBCXX_HAVE_LINUX_FUTEX && ATOMIC_INT_LOCK_FREE > 1)
216 template <
unsigned _Waiter_bit = 0x80000000>
217 class __atomic_futex_unsigned
219 typedef chrono::system_clock __clock_t;
223 condition_variable _M_condvar;
227 __atomic_futex_unsigned(
unsigned __data) : _M_data(__data)
230 _GLIBCXX_ALWAYS_INLINE
unsigned
233 unique_lock<mutex> __lock(_M_mutex);
237 _GLIBCXX_ALWAYS_INLINE
unsigned
238 _M_load_when_not_equal(
unsigned __val,
memory_order __mo)
240 unique_lock<mutex> __lock(_M_mutex);
241 while (_M_data == __val)
242 _M_condvar.wait(__lock);
246 _GLIBCXX_ALWAYS_INLINE
void
249 unique_lock<mutex> __lock(_M_mutex);
250 while (_M_data != __val)
251 _M_condvar.wait(__lock);
254 template<
typename _Rep,
typename _Period>
255 _GLIBCXX_ALWAYS_INLINE
bool
256 _M_load_when_equal_for(
unsigned __val,
memory_order __mo,
257 const chrono::duration<_Rep, _Period>& __rtime)
259 unique_lock<mutex> __lock(_M_mutex);
260 return _M_condvar.wait_for(__lock, __rtime,
261 [&] {
return _M_data == __val;});
264 template<
typename _Clock,
typename _Duration>
265 _GLIBCXX_ALWAYS_INLINE
bool
266 _M_load_when_equal_until(
unsigned __val,
memory_order __mo,
267 const chrono::time_point<_Clock, _Duration>& __atime)
269 unique_lock<mutex> __lock(_M_mutex);
270 return _M_condvar.wait_until(__lock, __atime,
271 [&] {
return _M_data == __val;});
274 _GLIBCXX_ALWAYS_INLINE
void
277 unique_lock<mutex> __lock(_M_mutex);
279 _M_condvar.notify_all();
283 #endif // _GLIBCXX_HAVE_LINUX_FUTEX && ATOMIC_INT_LOCK_FREE > 1
284 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
286 _GLIBCXX_END_NAMESPACE_VERSION
memory_order
Enumeration for memory_order.
ISO C++ entities toplevel namespace is std.