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