1#ifndef NEFORCE_CORE_ASYNC_ATOMIC_WAIT_HPP__
2#define NEFORCE_CORE_ASYNC_ATOMIC_WAIT_HPP__
14NEFORCE_BEGIN_NAMESPACE__
35 bool operator()()
const noexcept {
return false; }
52template <
typename Pred,
typename Spin = default_spin_policy>
54 constexpr auto atomic_spin_count = 16;
55 constexpr auto atomic_spin_count_relax = 12;
56 for (
auto idx = 0; idx < atomic_spin_count; ++idx) {
60 if (idx < atomic_spin_count_relax) {
85struct waiter_pool_base {
86 static constexpr auto align_inner = 64;
88 alignas(align_inner) platform_wait_t wait = 0;
89 alignas(align_inner) platform_wait_t value = 0;
91 waiter_pool_base() =
default;
98 void waiter_enter_wait() noexcept {
99#ifdef NEFORCE_PLATFORM_WINDOWS
100 ::_InterlockedIncrement(&wait);
102 __atomic_fetch_add(&wait, 1, __ATOMIC_SEQ_CST);
111 void waiter_leave_wait() noexcept {
112#ifdef NEFORCE_PLATFORM_WINDOWS
113 ::_InterlockedDecrement(&wait);
115 __atomic_fetch_sub(&wait, 1, __ATOMIC_RELEASE);
123 NEFORCE_NODISCARD
bool waiter_waiting() const noexcept {
124#ifdef NEFORCE_PLATFORM_WINDOWS
128 __atomic_load(&wait, &res, __ATOMIC_SEQ_CST);
139 void waiter_notify(platform_wait_t* addr,
bool all,
const bool bare)
const noexcept {
140 if (addr == &value) {
141#ifdef NEFORCE_PLATFORM_WINDOWS
142 ::_InterlockedIncrement(addr);
144 __atomic_fetch_add(addr, 1, __ATOMIC_SEQ_CST);
148 if (bare || waiter_waiting()) {
160 static waiter_pool_base& waiter_for(
const void* addr)
noexcept {
162 static waiter_pool_base waiter[pool_size];
163 const auto key = (
reinterpret_cast<uintptr_t>(addr) >> 2) % pool_size;
174struct waiter_pool : waiter_pool_base {
180 NEFORCE_ALWAYS_INLINE
void waiter_do_wait(platform_wait_t* addr,
const platform_wait_t old)
const noexcept {
205 template <
typename U>
206 static constexpr bool platform_wait_valid_v =
207 is_scalar_v<U> &&
sizeof(U) ==
sizeof(platform_wait_t) &&
alignof(U*) >=
alignof(platform_wait_t);
209 template <
typename U, enable_if_t<platform_wait_val
id_v<U>,
int> = 0>
210 NEFORCE_ALWAYS_INLINE
static void waiter_do_spin_v_impl(platform_wait_t* ,
const U& old,
211 platform_wait_t& value) {
214 template <
typename U, enable_if_t<!platform_wait_val
id_v<U>,
int> = 0>
215 NEFORCE_ALWAYS_INLINE
static void waiter_do_spin_v_impl(platform_wait_t* addr,
const U& ,
216 platform_wait_t& value) {
217#ifdef NEFORCE_PLATFORM_WINDOWS
218 value = ::_InterlockedExchangeAdd(addr, 0);
220 __atomic_load(addr, &value, __ATOMIC_ACQUIRE);
225 using waiter_type = T;
227 waiter_type& waiter_;
233 template <
typename U>
234 static enable_if_t<platform_wait_valid_v<U>,
platform_wait_t*> waiter_wait_addr(
const U* addr,
242 template <
typename U>
243 static enable_if_t<!platform_wait_valid_v<U>,
platform_wait_t*> waiter_wait_addr(
const U* ,
244 platform_wait_t* wait) {
251 static waiter_type& waiter_for(
const void* addr)
noexcept {
252 static_assert(
sizeof(waiter_type) ==
sizeof(waiter_pool_base),
253 "waiter_for should be same size with waiter_pool_base");
254 auto& res = waiter_pool_base::waiter_for(addr);
255 return reinterpret_cast<waiter_type&
>(res);
263 template <
typename U>
264 explicit waiter_base(
const U* addr) noexcept :
265 waiter_(waiter_base::waiter_for(addr)),
266 addr_(waiter_base::waiter_wait_addr(addr, &waiter_.value)) {}
273 void waiter_notify(
bool all,
bool bare =
false) noexcept { waiter_.waiter_notify(addr_, all, bare); }
278 template <
typename U,
typename Func,
typename Spin = default_spin_policy>
279 static bool waiter_do_spin_v(platform_wait_t* addr,
const U& old, Func f, platform_wait_t& value,
280 Spin spin = Spin{}) {
281 auto const pred = [=] {
return _NEFORCE memory_compare<U>(old, f()) != 0; };
282 waiter_base::waiter_do_spin_v_impl(addr, old, value);
289 template <
typename U,
typename Func,
typename Spin = default_spin_policy>
290 bool waiter_do_spin_v(
const U& old, Func f, platform_wait_t& value, Spin spin = Spin{}) {
291 return waiter_base::waiter_do_spin_v(addr_, old, f, value, spin);
297 template <
typename Pred,
typename Spin = default_spin_policy>
298 static bool waiter_do_spin(
const platform_wait_t* addr, Pred pred, platform_wait_t& value, Spin spin = Spin{}) {
299#ifdef NEFORCE_PLATFORM_WINDOWS
300 value = ::_InterlockedExchangeAdd(
const_cast<volatile LONG*
>(addr), 0);
302 __atomic_load(addr, &value, __ATOMIC_ACQUIRE);
310 template <
typename Pred,
typename Spin = default_spin_policy>
311 bool waiter_do_spin(Pred pred, platform_wait_t& value, Spin spin = Spin{}) {
312 return waiter_base::waiter_do_spin(addr_, pred, value, spin);
324template <
typename EntersWait>
325struct waiter : waiter_base<waiter_pool> {
327 using base_type = waiter_base<waiter_pool>;
330 template <
bool Wait = EntersWait::value, enable_if_t<Wait,
int> = 0>
331 NEFORCE_ALWAYS_INLINE
void enter() const noexcept {
332 waiter_.waiter_enter_wait();
334 template <
bool Wait = EntersWait::value, enable_if_t<!Wait,
int> = 0>
335 NEFORCE_ALWAYS_INLINE
void enter() const noexcept {}
337 template <
bool Wait = EntersWait::value, enable_if_t<Wait,
int> = 0>
338 NEFORCE_ALWAYS_INLINE
void leave() const noexcept {
339 waiter_.waiter_leave_wait();
341 template <
bool Wait = EntersWait::value, enable_if_t<!Wait,
int> = 0>
342 NEFORCE_ALWAYS_INLINE
void leave() const noexcept {}
350 template <
typename T>
351 explicit waiter(
const T* addr) noexcept :
359 ~waiter() { leave(); }
370 template <
typename T,
typename Func>
371 void waiter_do_wait_v(T old, Func f) {
374 if (base_type::waiter_do_spin_v(old, f, value)) {
377 waiter_.waiter_do_wait(base_type::addr_, value);
378 }
while (_NEFORCE memory_compare<T>(old, f()) == 0);
386 template <
typename Pred>
387 void waiter_do_wait(Pred pred)
noexcept {
390 if (base_type::waiter_do_spin(pred, value)) {
393 waiter_.waiter_do_wait(base_type::addr_, value);
399using enters_wait = waiter<true_type>;
402using bare_wait = waiter<false_type>;
417template <
typename T,
typename Func>
419 inner::enters_wait waiter(addr);
420 waiter.waiter_do_wait_v(old, f);
432template <
typename T,
typename Pred>
434 inner::enters_wait waiter(addr);
435 waiter.waiter_do_wait(pred);
449 inner::bare_wait waiter(addr);
450 waiter.waiter_notify(all);
457NEFORCE_END_NAMESPACE__
void atomic_wait_address_v(const T *addr, T old, Func f) noexcept
基于值的原子等待
void atomic_wait_address(const T *addr, Pred pred) noexcept
基于谓词的原子等待
bool atomic_spin(Pred &pred, Spin spin=Spin{}) noexcept
原子自旋等待
void atomic_notify_address(const T *addr, const bool all) noexcept
原子通知
void futex_notify(void *addr, bool all) noexcept
通知等待的线程
long platform_wait_t
平台等待类型别名
void futex_wait(void *addr, platform_wait_t value) noexcept
无限期等待FUTEX
constexpr void * memory_copy(void *__restrict dest, const void *__restrict src, size_t count) noexcept
从源内存复制到目标内存