1#ifndef MSTL_CORE_ASYNC_ATOMIC_WAIT_HPP__
2#define MSTL_CORE_ASYNC_ATOMIC_WAIT_HPP__
29 bool operator ()()
const noexcept {
return false; }
46template <
typename Pred,
typename Spin = default_spin_policy>
48 constexpr auto atomic_spin_count = 16;
49 constexpr auto atomic_spin_count_relax = 12;
50 for (
auto idx = 0; idx < atomic_spin_count; ++idx) {
51 if (pred())
return true;
52 if (idx < atomic_spin_count_relax) {
60 if (pred())
return true;
75struct waiter_pool_base {
76 static constexpr auto align_inner = 64;
81 waiter_pool_base() =
default;
88 void waiter_enter_wait() noexcept {
89#ifdef MSTL_PLATFORM_WINDOWS__
90 ::_InterlockedIncrement(&
wait);
92 __atomic_fetch_add(&
wait, 1, __ATOMIC_SEQ_CST);
101 void waiter_leave_wait() noexcept {
102#ifdef MSTL_PLATFORM_WINDOWS__
103 ::_InterlockedDecrement(&
wait);
105 __atomic_fetch_sub(&
wait, 1, __ATOMIC_RELEASE);
113 bool waiter_waiting() const noexcept {
114#ifdef MSTL_PLATFORM_WINDOWS__
119 __atomic_load(&
wait, &res, __ATOMIC_SEQ_CST);
130 void waiter_notify(
platform_wait_t* addr,
bool all,
const bool bare)
const noexcept {
131 if (addr == &value) {
132#ifdef MSTL_PLATFORM_WINDOWS__
133 ::_InterlockedIncrement(addr);
135 __atomic_fetch_add(addr, 1, __ATOMIC_SEQ_CST);
139 if (bare || waiter_waiting()) {
151 static waiter_pool_base& waiter_for(
const void* addr)
noexcept{
153 static waiter_pool_base waiter[pool_size];
154 const auto key = (
reinterpret_cast<uintptr_t>(addr) >> 2) % pool_size;
165struct waiter_pool : waiter_pool_base {
187 template <
typename U, enable_if_t<platform_wait_val
id_v<U>,
int> = 0>
188 MSTL_ALWAYS_INLINE
static void waiter_do_spin_v_impl(
192 template <
typename U, enable_if_t<!platform_wait_val
id_v<U>,
int> = 0>
193 MSTL_ALWAYS_INLINE
static void waiter_do_spin_v_impl(
195#ifdef MSTL_PLATFORM_WINDOWS__
196 value = ::_InterlockedExchangeAdd(addr, 0);
198 __atomic_load(addr, &value, __ATOMIC_ACQUIRE);
203 using waiter_type = T;
205 waiter_type& waiter_;
211 template <
typename U>
220 template <
typename U>
229 static waiter_type& waiter_for(
const void* addr)
noexcept {
230 static_assert(
sizeof(waiter_type) ==
sizeof(waiter_pool_base),
231 "waiter_for should be same size with waiter_pool_base");
232 auto& res = waiter_pool_base::waiter_for(addr);
233 return reinterpret_cast<waiter_type&
>(res);
241 template <
typename U>
242 explicit waiter_base(
const U* addr) noexcept
243 : waiter_(waiter_base::waiter_for(addr)),
244 addr_(waiter_base::waiter_wait_addr(addr, &waiter_.value)) {}
251 void waiter_notify(
bool all,
bool bare =
false) noexcept {
252 waiter_.waiter_notify(addr_, all, bare);
258 template <
typename U,
typename Func,
typename Spin = default_spin_policy>
261 auto const pred = [=] {
264 waiter_base::waiter_do_spin_v_impl(addr, old, value);
271 template <
typename U,
typename Func,
typename Spin = default_spin_policy>
272 bool waiter_do_spin_v(
const U& old, Func f,
platform_wait_t& value, Spin spin = Spin{}) {
273 return waiter_base::waiter_do_spin_v(addr_, old, f, value, spin);
279 template <
typename Pred,
typename Spin = default_spin_policy>
282#ifdef MSTL_PLATFORM_WINDOWS__
283 value = ::_InterlockedExchangeAdd(
const_cast<volatile LONG*
>(addr), 0);
285 __atomic_load(addr, &value, __ATOMIC_ACQUIRE);
293 template <
typename Pred,
typename Spin = default_spin_policy>
294 bool waiter_do_spin(Pred pred,
platform_wait_t& value, Spin spin = Spin{}) {
295 return waiter_base::waiter_do_spin(addr_, pred, value, spin);
307template <
typename EntersWait>
308struct waiter : waiter_base<waiter_pool> {
310 using base_type = waiter_base<waiter_pool>;
313 template <
bool Wait = EntersWait::value, enable_if_t<Wait,
int> = 0>
314 MSTL_ALWAYS_INLINE
void enter() const noexcept {
315 waiter_.waiter_enter_wait();
317 template <
bool Wait = EntersWait::value, enable_if_t<!Wait,
int> = 0>
318 MSTL_ALWAYS_INLINE
void enter() const noexcept {}
320 template <
bool Wait = EntersWait::value, enable_if_t<Wait,
int> = 0>
321 MSTL_ALWAYS_INLINE
void leave() const noexcept {
322 waiter_.waiter_leave_wait();
324 template <
bool Wait = EntersWait::value, enable_if_t<!Wait,
int> = 0>
325 MSTL_ALWAYS_INLINE
void leave() const noexcept {}
333 template <
typename T>
334 explicit waiter(
const T* addr) noexcept
355 template <
typename T,
typename Func>
356 void waiter_do_wait_v(T old, Func f) {
359 if (base_type::waiter_do_spin_v(old, f, value))
return;
360 waiter_.waiter_do_wait(base_type::addr_, value);
369 template <
typename Pred>
370 void waiter_do_wait(Pred pred)
noexcept {
373 if (base_type::waiter_do_spin(pred, value))
return;
374 waiter_.waiter_do_wait(base_type::addr_, value);
380using enters_wait = waiter<true_type>;
383using bare_wait = waiter<false_type>;
398template <
typename T,
typename Func>
400 _INNER enters_wait waiter(addr);
401 waiter.waiter_do_wait_v(old, f);
413template <
typename T,
typename Pred>
415 _INNER enters_wait waiter(addr);
416 waiter.waiter_do_wait(pred);
430 _INNER bare_wait waiter(addr);
431 waiter.waiter_notify(all);
void atomic_wait_address(const T *addr, Pred pred) noexcept
基于谓词的原子等待
bool atomic_spin(Pred &pred, Spin spin=Spin{}) noexcept
原子自旋等待
void atomic_wait_address_v(const T *addr, T old, Func f) noexcept
基于值的原子等待
void atomic_notify_address(const T *addr, const bool all) noexcept
原子通知
void MSTL_API futex_notify(void *addr, bool all) noexcept
通知等待的线程
int platform_wait_t
平台等待类型别名
void MSTL_API futex_wait(void *addr, platform_wait_t value) noexcept
无限期等待FUTEX
MSTL_CONSTEXPR14 void * memory_copy(void *MSTL_RESTRICT dest, const void *MSTL_RESTRICT src, size_t count) noexcept
从源内存复制到目标内存
MSTL_PURE_FUNCTION MSTL_CONSTEXPR14 int memory_compare(const void *lhs, const void *rhs, size_t count) noexcept
比较两个内存区域的内容
#define _MSTL
全局命名空间MSTL前缀
#define MSTL_END_INNER__
结束inner命名空间
#define _INNER
inner命名空间前缀
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
#define MSTL_BEGIN_INNER__
开始inner命名空间
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名