xref: /aosp_15_r20/external/cronet/base/tracing/perfetto_task_runner.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2018 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 #include "base/tracing/perfetto_task_runner.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/auto_reset.h"
11 #include "base/containers/contains.h"
12 #include "base/functional/bind.h"
13 #include "base/notreached.h"
14 #include "base/task/common/checked_lock_impl.h"
15 #include "base/task/common/scoped_defer_task_posting.h"
16 #include "base/task/sequenced_task_runner.h"
17 #include "base/task/thread_pool.h"
18 #include "base/task/thread_pool/thread_pool_instance.h"
19 #include "base/tracing/tracing_tls.h"
20 #include "build/build_config.h"
21 
22 #include "base/debug/stack_trace.h"
23 
24 namespace base {
25 namespace tracing {
26 
PerfettoTaskRunner(scoped_refptr<base::SequencedTaskRunner> task_runner)27 PerfettoTaskRunner::PerfettoTaskRunner(
28     scoped_refptr<base::SequencedTaskRunner> task_runner)
29     : task_runner_(std::move(task_runner)) {}
30 
~PerfettoTaskRunner()31 PerfettoTaskRunner::~PerfettoTaskRunner() {
32   DCHECK(GetOrCreateTaskRunner()->RunsTasksInCurrentSequence());
33 #if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
34   fd_controllers_.clear();
35 #endif  // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
36 }
37 
PostTask(std::function<void ()> task)38 void PerfettoTaskRunner::PostTask(std::function<void()> task) {
39   PostDelayedTask(task, /* delay_ms */ 0);
40 }
41 
PostDelayedTask(std::function<void ()> task,uint32_t delay_ms)42 void PerfettoTaskRunner::PostDelayedTask(std::function<void()> task,
43                                          uint32_t delay_ms) {
44   base::ScopedDeferTaskPosting::PostOrDefer(
45       GetOrCreateTaskRunner(), FROM_HERE,
46       base::BindOnce(
47           [](std::function<void()> task) {
48             // We block any trace events that happens while any
49             // Perfetto task is running, or we'll get deadlocks in
50             // situations where the StartupTraceWriterRegistry tries
51             // to bind a writer which in turn causes a PostTask where
52             // a trace event can be emitted, which then deadlocks as
53             // it needs a new chunk from the same StartupTraceWriter
54             // which we're trying to bind and are keeping the lock
55             // to.
56             // TODO(oysteine): Try to see if we can be more selective
57             // about this.
58             const AutoReset<bool> resetter(GetThreadIsInTraceEvent(), true,
59                                            false);
60             task();
61           },
62           task),
63       base::Milliseconds(delay_ms));
64 }
65 
RunsTasksOnCurrentThread() const66 bool PerfettoTaskRunner::RunsTasksOnCurrentThread() const {
67   DCHECK(task_runner_);
68   return task_runner_->RunsTasksInCurrentSequence();
69 }
70 
71 // PlatformHandle is an int on POSIX, a HANDLE on Windows.
AddFileDescriptorWatch(perfetto::base::PlatformHandle fd,std::function<void ()> callback)72 void PerfettoTaskRunner::AddFileDescriptorWatch(
73     perfetto::base::PlatformHandle fd,
74     std::function<void()> callback) {
75 #if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
76   DCHECK(GetOrCreateTaskRunner()->RunsTasksInCurrentSequence());
77   DCHECK(!base::Contains(fd_controllers_, fd));
78   // Set up the |fd| in the map to signal intent to add a watch. We need to
79   // PostTask the WatchReadable creation because if we do it in this task we'll
80   // race with perfetto setting up the connection on this task and the IO thread
81   // setting up epoll on the |fd|. Using a CancelableOnceClosure ensures that
82   // the |fd| won't be added for watch if RemoveFileDescriptorWatch is called.
83   fd_controllers_[fd].callback.Reset(
84       base::BindOnce(
85           [](PerfettoTaskRunner* perfetto_runner, int fd,
86              std::function<void()> callback) {
87             DCHECK(perfetto_runner->GetOrCreateTaskRunner()
88                        ->RunsTasksInCurrentSequence());
89             // When this callback runs, we must not have removed |fd|'s watch.
90             CHECK(base::Contains(perfetto_runner->fd_controllers_, fd));
91             auto& controller_and_cb = perfetto_runner->fd_controllers_[fd];
92             // We should never overwrite an existing watch.
93             CHECK(!controller_and_cb.controller);
94             controller_and_cb.controller =
95                 base::FileDescriptorWatcher::WatchReadable(
96                     fd, base::BindRepeating(
97                             [](std::function<void()> callback) { callback(); },
98                             std::move(callback)));
99           },
100           base::Unretained(this), fd, std::move(callback)));
101   task_runner_->PostTask(FROM_HERE, fd_controllers_[fd].callback.callback());
102 #else   // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
103   NOTREACHED();
104 #endif  // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
105 }
106 
RemoveFileDescriptorWatch(perfetto::base::PlatformHandle fd)107 void PerfettoTaskRunner::RemoveFileDescriptorWatch(
108     perfetto::base::PlatformHandle fd) {
109 #if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
110   DCHECK(GetOrCreateTaskRunner()->RunsTasksInCurrentSequence());
111   DCHECK(base::Contains(fd_controllers_, fd));
112   // This also cancels the base::FileDescriptorWatcher::WatchReadable() task if
113   // it's pending.
114   fd_controllers_.erase(fd);
115 #else   // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
116   NOTREACHED();
117 #endif  // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
118 }
119 
ResetTaskRunnerForTesting(scoped_refptr<base::SequencedTaskRunner> task_runner)120 void PerfettoTaskRunner::ResetTaskRunnerForTesting(
121     scoped_refptr<base::SequencedTaskRunner> task_runner) {
122   task_runner_ = std::move(task_runner);
123 }
124 
SetTaskRunner(scoped_refptr<base::SequencedTaskRunner> task_runner)125 void PerfettoTaskRunner::SetTaskRunner(
126     scoped_refptr<base::SequencedTaskRunner> task_runner) {
127   DCHECK(!task_runner_);
128   task_runner_ = std::move(task_runner);
129 }
130 
131 scoped_refptr<base::SequencedTaskRunner>
GetOrCreateTaskRunner()132 PerfettoTaskRunner::GetOrCreateTaskRunner() {
133   // TODO(eseckler): This is not really thread-safe. We should probably add a
134   // lock around this. At the moment we can get away without one because this
135   // method is called for the first time on the process's main thread before the
136   // tracing service connects.
137   if (!task_runner_) {
138     DCHECK(base::ThreadPoolInstance::Get());
139     task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
140         {base::MayBlock(), base::TaskPriority::USER_BLOCKING});
141   }
142 
143   return task_runner_;
144 }
145 
146 #if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
147 PerfettoTaskRunner::FDControllerAndCallback::FDControllerAndCallback() =
148     default;
149 
150 PerfettoTaskRunner::FDControllerAndCallback::~FDControllerAndCallback() =
151     default;
152 #endif  // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
153 
154 }  // namespace tracing
155 }  // namespace base
156