xref: /aosp_15_r20/external/cronet/base/synchronization/waitable_event.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2022 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/trace_event/base_tracing.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/tracing_buildflags.h"
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker namespace base {
13*6777b538SAndroid Build Coastguard Worker 
~WaitableEvent()14*6777b538SAndroid Build Coastguard Worker WaitableEvent::~WaitableEvent() {
15*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(ENABLE_BASE_TRACING)
16*6777b538SAndroid Build Coastguard Worker   // As requested in the documentation of perfetto::Flow::FromPointer, we should
17*6777b538SAndroid Build Coastguard Worker   // emit a TerminatingFlow(this) from our destructor if we ever emitted a
18*6777b538SAndroid Build Coastguard Worker   // Flow(this) which may be unmatched since the ptr value of `this` may be
19*6777b538SAndroid Build Coastguard Worker   // reused after this destructor. This can happen if a signaled event is never
20*6777b538SAndroid Build Coastguard Worker   // waited upon (or isn't the one to satisfy a WaitMany condition).
21*6777b538SAndroid Build Coastguard Worker   if (!only_used_while_idle_) {
22*6777b538SAndroid Build Coastguard Worker     // Check the tracing state to avoid an unnecessary syscall on destruction
23*6777b538SAndroid Build Coastguard Worker     // (which can be performance sensitive, crbug.com/40275035).
24*6777b538SAndroid Build Coastguard Worker     static const uint8_t* flow_enabled =
25*6777b538SAndroid Build Coastguard Worker         TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("wakeup.flow,toplevel.flow");
26*6777b538SAndroid Build Coastguard Worker     if (*flow_enabled && IsSignaled()) {
27*6777b538SAndroid Build Coastguard Worker       TRACE_EVENT_INSTANT("wakeup.flow,toplevel.flow",
28*6777b538SAndroid Build Coastguard Worker                           "~WaitableEvent while Signaled",
29*6777b538SAndroid Build Coastguard Worker                           perfetto::TerminatingFlow::FromPointer(this));
30*6777b538SAndroid Build Coastguard Worker     }
31*6777b538SAndroid Build Coastguard Worker   }
32*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
33*6777b538SAndroid Build Coastguard Worker }
34*6777b538SAndroid Build Coastguard Worker 
Signal()35*6777b538SAndroid Build Coastguard Worker void WaitableEvent::Signal() {
36*6777b538SAndroid Build Coastguard Worker   // Must be ordered before SignalImpl() to guarantee it's emitted before the
37*6777b538SAndroid Build Coastguard Worker   // matching TerminatingFlow in TimedWait().
38*6777b538SAndroid Build Coastguard Worker   if (!only_used_while_idle_) {
39*6777b538SAndroid Build Coastguard Worker     TRACE_EVENT_INSTANT("wakeup.flow,toplevel.flow", "WaitableEvent::Signal",
40*6777b538SAndroid Build Coastguard Worker                         perfetto::Flow::FromPointer(this));
41*6777b538SAndroid Build Coastguard Worker   }
42*6777b538SAndroid Build Coastguard Worker   SignalImpl();
43*6777b538SAndroid Build Coastguard Worker }
44*6777b538SAndroid Build Coastguard Worker 
Wait()45*6777b538SAndroid Build Coastguard Worker void WaitableEvent::Wait() {
46*6777b538SAndroid Build Coastguard Worker   const bool result = TimedWait(TimeDelta::Max());
47*6777b538SAndroid Build Coastguard Worker   DCHECK(result) << "TimedWait() should never fail with infinite timeout";
48*6777b538SAndroid Build Coastguard Worker }
49*6777b538SAndroid Build Coastguard Worker 
TimedWait(TimeDelta wait_delta)50*6777b538SAndroid Build Coastguard Worker bool WaitableEvent::TimedWait(TimeDelta wait_delta) {
51*6777b538SAndroid Build Coastguard Worker   if (wait_delta <= TimeDelta())
52*6777b538SAndroid Build Coastguard Worker     return IsSignaled();
53*6777b538SAndroid Build Coastguard Worker 
54*6777b538SAndroid Build Coastguard Worker   // Consider this thread blocked for scheduling purposes. Ignore this for
55*6777b538SAndroid Build Coastguard Worker   // non-blocking WaitableEvents.
56*6777b538SAndroid Build Coastguard Worker   std::optional<internal::ScopedBlockingCallWithBaseSyncPrimitives>
57*6777b538SAndroid Build Coastguard Worker       scoped_blocking_call;
58*6777b538SAndroid Build Coastguard Worker   if (!only_used_while_idle_) {
59*6777b538SAndroid Build Coastguard Worker     scoped_blocking_call.emplace(FROM_HERE, BlockingType::MAY_BLOCK);
60*6777b538SAndroid Build Coastguard Worker   }
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker   const bool result = TimedWaitImpl(wait_delta);
63*6777b538SAndroid Build Coastguard Worker 
64*6777b538SAndroid Build Coastguard Worker   if (result && !only_used_while_idle_) {
65*6777b538SAndroid Build Coastguard Worker     TRACE_EVENT_INSTANT("wakeup.flow,toplevel.flow",
66*6777b538SAndroid Build Coastguard Worker                         "WaitableEvent::Wait Complete",
67*6777b538SAndroid Build Coastguard Worker                         perfetto::TerminatingFlow::FromPointer(this));
68*6777b538SAndroid Build Coastguard Worker   }
69*6777b538SAndroid Build Coastguard Worker 
70*6777b538SAndroid Build Coastguard Worker   return result;
71*6777b538SAndroid Build Coastguard Worker }
72*6777b538SAndroid Build Coastguard Worker 
WaitMany(WaitableEvent ** events,size_t count)73*6777b538SAndroid Build Coastguard Worker size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) {
74*6777b538SAndroid Build Coastguard Worker   DCHECK(count) << "Cannot wait on no events";
75*6777b538SAndroid Build Coastguard Worker   internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
76*6777b538SAndroid Build Coastguard Worker       FROM_HERE, BlockingType::MAY_BLOCK);
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker   const size_t signaled_id = WaitManyImpl(events, count);
79*6777b538SAndroid Build Coastguard Worker   WaitableEvent* const signaled_event = events[signaled_id];
80*6777b538SAndroid Build Coastguard Worker   if (!signaled_event->only_used_while_idle_) {
81*6777b538SAndroid Build Coastguard Worker     TRACE_EVENT_INSTANT("wakeup.flow,toplevel.flow",
82*6777b538SAndroid Build Coastguard Worker                         "WaitableEvent::WaitMany Complete",
83*6777b538SAndroid Build Coastguard Worker                         perfetto::TerminatingFlow::FromPointer(signaled_event));
84*6777b538SAndroid Build Coastguard Worker   }
85*6777b538SAndroid Build Coastguard Worker   return signaled_id;
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker }  // namespace base
89