一呼百應, "one call, a hundred responses"
Loading...
Searching...
No Matches
wait.hpp
Go to the documentation of this file.
1#pragma once
2
15#include <cstdint>
16#include <x86intrin.h>
17#include "attributes/common.hpp"
19#include "cpuid.hpp"
20
21namespace ein {
24
27template <typename T>
28concept waiter = requires (volatile void * p, uint32_t t) {
29 bool(T::supported);
30 T::monitor(p);
31 T::mwait(t);
32};
33
39template <waiter W> ein_flatten
40void wait_until(volatile auto * p, auto f) noexcept ein_blocking {
41 [[assume(W::supported)]];
42 while (!f(p)) {
43 W::monitor(p);
44 if (!f(p))
45 W::mwait(0);
46 }
47}
48
50struct mwaitx {
51 using timer_t = uint64_t;
52 ein_inline ein_artificial static void monitor(volatile void * p) noexcept { _mm_monitorx(const_cast<void*>(p),0,0); }
53 ein_inline ein_artificial static void mwait(uint32_t timer = 0) noexcept ein_blocking { _mm_mwaitx(0,0,timer); }
55 static const bool supported;
56};
57
58
60struct umwait {
61 using timer_t = uint64_t;
62 ein_inline ein_artificial static void monitor(volatile void * p) noexcept { return _umonitor(const_cast<void*>(p)); }
63 ein_inline ein_artificial static uint8_t mwait(uint32_t timer = 0) noexcept ein_blocking { return _umwait(1,timer); }
65 static const bool supported;
66};
67
69struct spin {
70 using timer_t = uint64_t;
71 ein_inline ein_artificial static void monitor(volatile void *) noexcept {}
72 ein_inline ein_artificial static void mwait(uint32_t = 0) noexcept ein_blocking { _mm_pause(); }
74 inline static constinit bool supported = true;
75};
76
84auto with_waiter(auto k) noexcept {
85 if (mwaitx::supported) return k.template operator()<mwaitx>();
86 else if (umwait::supported) return k.template operator()<umwait>();
87 else k.template operator()<spin>();
88}
89
91}
92
93#if defined(EIN_TESTING) || defined(EIN_TESTING_WAIT)
94#include <atomic>
95#include <thread>
96#include <chrono>
97namespace {
98 // Mock waiter that simulates waiting behavior
99 struct mock_waiter {
100 static inline bool supported = true;
101 static inline std::atomic<bool> monitor_called = false;
102 static inline std::atomic<bool> mwait_called = false;
103
104 static void monitor(volatile void*) noexcept {
105 monitor_called.store(true);
106 }
107
108 static void mwait(uint32_t timer = 0) noexcept {
109 mwait_called.store(true);
110 std::this_thread::sleep_for(std::chrono::milliseconds(timer));
111 }
112 };
113}
114
115TEST_CASE("wait","[wait]") {
116
117 SECTION("wait_until with mock_waiter") {
118 using namespace ein;
119
120 volatile int data = 0;
121 auto predicate = [](volatile int* p) { return *p == 42; };
122
123 std::thread updater([&data]() {
124 std::this_thread::sleep_for(std::chrono::milliseconds(100));
125 data = 42;
126 });
127
128 wait_until<mock_waiter>(&data, predicate);
129
130 CHECK(mock_waiter::monitor_called.load());
131 CHECK(mock_waiter::mwait_called.load());
132 CHECK(data == 42);
133
134 updater.join();
135 }
136
137 SECTION("wait_until with platform waiter") {
138 using namespace ein;
139
140 volatile int data = 0;
141 auto predicate = [](volatile int* p) { return *p == 42; };
142
143 std::thread updater([&data]() {
144 std::this_thread::sleep_for(std::chrono::milliseconds(100));
145 data = 42;
146 });
147
148 with_waiter([&data,predicate] <waiter w> {
149 wait_until<w>(&data, predicate);
150 });
151
152 CHECK(data == 42);
153
154 updater.join();
155 }
156}
157#endif
some way to wait for a value to change
Definition wait.hpp:28
#define ein_artificial
[[artificial]].
Definition common.hpp:220
#define ein_flatten
portable [[flatten]]
Definition common.hpp:203
#define ein_inline
inline [[always_inline]]
Definition common.hpp:188
#define ein_blocking
Declares a function potentially blocks. Prevents inference of ein_nonblocking.
uint64_t timer_t
Definition wait.hpp:70
static void mwait(uint32_t=0) noexcept ein_blocking
Definition wait.hpp:72
uint64_t timer_t
Definition wait.hpp:51
static void monitor(volatile void *p) noexcept
Definition wait.hpp:52
static uint8_t mwait(uint32_t timer=0) noexcept ein_blocking
Definition wait.hpp:63
static void monitor(volatile void *p) noexcept
Definition wait.hpp:62
static void monitor(volatile void *) noexcept
Definition wait.hpp:71
static const bool supported
Definition wait.hpp:65
static const bool supported
Definition wait.hpp:55
static constinit bool supported
Definition wait.hpp:74
uint64_t timer_t
Definition wait.hpp:61
static void mwait(uint32_t timer=0) noexcept ein_blocking
Definition wait.hpp:53
auto with_waiter(auto k) noexcept
finds an appropriate waiter for the current CPU
Definition wait.hpp:84
ein_flatten void wait_until(volatile auto *p, auto f) noexcept ein_blocking
Wait until a predicate holds about a given memory location.
Definition wait.hpp:40
waiter using MONITORX/MWAITX for AMD
Definition wait.hpp:50
spin waiter using PAUSE
Definition wait.hpp:69
waiter using UMONITOR/UMWAIT for Intel
Definition wait.hpp:60
Definition cpuid.cpp:16