#include "base/synchronization/waitable_event.h"
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/trace_event/trace_event.h"
#include "base/tracing_buildflags.h"
namespace base {
WaitableEvent::~WaitableEvent() {
if (!only_used_while_idle_) {
static const uint8_t* flow_enabled =
TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("wakeup.flow,toplevel.flow");
if (*flow_enabled && IsSignaled()) {
TRACE_EVENT_INSTANT("wakeup.flow,toplevel.flow",
"~WaitableEvent while Signaled",
perfetto::TerminatingFlow::FromPointer(this));
}
}
}
void WaitableEvent::Signal() {
if (!only_used_while_idle_) {
TRACE_EVENT_INSTANT("wakeup.flow,toplevel.flow", "WaitableEvent::Signal",
perfetto::Flow::FromPointer(this));
}
SignalImpl();
}
void WaitableEvent::Wait() {
const bool result = TimedWait(TimeDelta::Max());
DCHECK(result) << "TimedWait() should never fail with infinite timeout";
}
bool WaitableEvent::TimedWait(TimeDelta wait_delta) {
if (wait_delta <= TimeDelta()) {
return IsSignaled();
}
std::optional<internal::ScopedBlockingCallWithBaseSyncPrimitives>
scoped_blocking_call;
if (!only_used_while_idle_) {
scoped_blocking_call.emplace(FROM_HERE, BlockingType::MAY_BLOCK);
}
const bool result = TimedWaitImpl(wait_delta);
if (result && !only_used_while_idle_) {
TRACE_EVENT_INSTANT("wakeup.flow,toplevel.flow",
"WaitableEvent::Wait Complete",
perfetto::TerminatingFlow::FromPointer(this));
}
return result;
}
size_t WaitableEvent::WaitMany(base::span<WaitableEvent*> events) {
DCHECK(!events.empty()) << "Cannot wait on no events";
internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
FROM_HERE, BlockingType::MAY_BLOCK);
const size_t signaled_id = WaitManyImpl(events);
WaitableEvent* const signaled_event = events[signaled_id];
if (!signaled_event->only_used_while_idle_) {
TRACE_EVENT_INSTANT("wakeup.flow,toplevel.flow",
"WaitableEvent::WaitMany Complete",
perfetto::TerminatingFlow::FromPointer(signaled_event));
}
return signaled_id;
}
}