-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathone_shot_event.cppm
More file actions
114 lines (89 loc) · 3.11 KB
/
Copy pathone_shot_event.cppm
File metadata and controls
114 lines (89 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
export module mcpplibs.cmp:one_shot_event;
import std;
import :when_all;
export namespace mcpplibs::cmp {
class OneShotEvent final {
public:
class Awaiter final {
private:
friend class OneShotEvent;
OneShotEvent* event_ {};
Awaiter* next_ {};
std::coroutine_handle<> continuation_ {};
explicit Awaiter(OneShotEvent& event) noexcept
: event_ { &event } {}
public:
Awaiter(const Awaiter&) = delete;
Awaiter& operator=(const Awaiter&) = delete;
Awaiter(Awaiter&&) = delete;
Awaiter& operator=(Awaiter&&) = delete;
[[nodiscard]] bool await_ready() const noexcept {
return event_->is_set();
}
[[nodiscard]] bool await_suspend(
std::coroutine_handle<> continuation) noexcept {
// 注册成功后 set() 可能立即恢复并销毁当前 awaiter
auto* const event = event_;
continuation_ = continuation;
return event->register_waiter_(*this);
}
constexpr void await_resume() const noexcept {}
};
private:
std::atomic<void*> state_ {};
[[nodiscard]] bool register_waiter_(Awaiter& waiter) noexcept;
public:
OneShotEvent() noexcept = default;
OneShotEvent(const OneShotEvent&) = delete;
OneShotEvent& operator=(const OneShotEvent&) = delete;
OneShotEvent(OneShotEvent&&) = delete;
OneShotEvent& operator=(OneShotEvent&&) = delete;
~OneShotEvent();
[[nodiscard]] bool is_set() const noexcept {
return state_.load(std::memory_order_acquire) ==
static_cast<const void*>(this);
}
void set() noexcept;
[[nodiscard]] Awaiter operator co_await() noexcept {
return Awaiter { *this };
}
};
inline OneShotEvent::~OneShotEvent() {
const auto state = state_.load(std::memory_order_relaxed);
// 等待节点属于协程帧,事件不能在仍引用这些节点时销毁
if (state != nullptr && state != static_cast<void*>(this)) {
std::terminate();
}
}
inline bool OneShotEvent::register_waiter_(Awaiter& waiter) noexcept {
const auto setState = static_cast<void*>(this);
auto state = state_.load(std::memory_order_acquire);
do {
if (state == setState) {
return false;
}
waiter.next_ = static_cast<Awaiter*>(state);
} while (!state_.compare_exchange_weak(
state,
&waiter,
std::memory_order_release,
std::memory_order_acquire));
return true;
}
inline void OneShotEvent::set() noexcept {
const auto setState = static_cast<void*>(this);
auto state = state_.exchange(setState, std::memory_order_acq_rel);
if (state == setState) {
return;
}
while (state != nullptr) {
// 恢复后当前节点可能立即销毁,因此先复制后继和句柄
auto* const waiter = static_cast<Awaiter*>(state);
auto* const next = waiter->next_;
const auto continuation = waiter->continuation_;
state = next;
detail::JoinStartQueue::Scope startScope {};
continuation.resume();
}
}
} // namespace mcpplibs::cmp