-
Notifications
You must be signed in to change notification settings - Fork 312
/
Copy pathsingle_use_event.cpp
96 lines (77 loc) · 2.97 KB
/
single_use_event.cpp
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
#include <userver/engine/single_use_event.hpp>
#include <userver/engine/exception.hpp>
#include <userver/engine/task/cancel.hpp>
#include <engine/impl/future_utils.hpp>
#include <engine/impl/wait_list_light.hpp>
#include <engine/task/task_context.hpp>
USERVER_NAMESPACE_BEGIN
namespace engine {
// Not considered implicitly noexcept on gcc-9.
// NOLINTNEXTLINE(hicpp-use-equals-default,modernize-use-equals-default)
SingleUseEvent::SingleUseEvent() noexcept {}
SingleUseEvent::~SingleUseEvent() = default;
void SingleUseEvent::Wait() {
switch (WaitUntil(Deadline{})) {
case FutureStatus::kReady:
break;
case FutureStatus::kTimeout:
UASSERT_MSG(
false,
"Timeout is not expected here due to unreachable "
"Deadline at Sleep"
);
#ifdef NDEBUG
[[fallthrough]];
#endif
case FutureStatus::kCancelled:
throw WaitInterruptedException(current_task::CancellationReason());
}
}
FutureStatus SingleUseEvent::WaitUntil(Deadline deadline) {
impl::TaskContext& current = current_task::GetCurrentTaskContext();
impl::FutureWaitStrategy wait_strategy{*this, current};
const auto wakeup_source = current.Sleep(wait_strategy, deadline);
// There are no spurious wakeups, because the event is single-use: if a task
// has ever been notified by this SingleUseEvent, then the task will find
// the SingleUseEvent ready once it wakes up.
if (wakeup_source == impl::TaskContext::WakeupSource::kWaitList) {
UASSERT(waiters_->IsSignaled());
}
return impl::ToFutureStatus(wakeup_source);
}
void SingleUseEvent::WaitNonCancellable() noexcept {
const TaskCancellationBlocker cancellation_blocker;
switch (WaitUntil(Deadline{})) {
case FutureStatus::kReady:
break;
case FutureStatus::kTimeout:
UASSERT_MSG(
false,
"Timeout is not expected here due to unreachable "
"Deadline at Sleep"
);
break;
case FutureStatus::kCancelled:
UASSERT_MSG(
false,
"Cancellation should have been blocked "
"by TaskCancellationBlocker"
);
break;
}
}
void SingleUseEvent::Send() noexcept {
UASSERT_MSG(!waiters_->IsSignaled(), "Multiple producers detected for the same SingleUseEvent");
waiters_->SetSignalAndWakeupOne();
}
bool SingleUseEvent::IsReady() const noexcept { return waiters_->IsSignaled(); }
impl::EarlyWakeup SingleUseEvent::TryAppendWaiter(impl::TaskContext& waiter) {
return impl::EarlyWakeup{waiters_->GetSignalOrAppend(&waiter)};
}
void SingleUseEvent::RemoveWaiter(impl::TaskContext& waiter) noexcept { waiters_->Remove(waiter); }
void SingleUseEvent::RethrowErrorResult() const {
// TODO support failure states in SingleUseEvent, for WaitAllChecked?
}
void SingleUseEvent::AfterWait() noexcept {}
} // namespace engine
USERVER_NAMESPACE_END