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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/tracing/perfetto_task_runner.h"
#include <memory>
#include <utility>
#include "base/auto_reset.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/notreached.h"
#include "base/task/common/checked_lock_impl.h"
#include "base/task/common/scoped_defer_task_posting.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/tracing/tracing_tls.h"
#include "build/build_config.h"
#include "base/debug/stack_trace.h"
namespace base {
namespace tracing {
PerfettoTaskRunner::PerfettoTaskRunner(
scoped_refptr<base::SequencedTaskRunner> task_runner)
: task_runner_(std::move(task_runner)) {}
PerfettoTaskRunner::~PerfettoTaskRunner() {
DCHECK(GetOrCreateTaskRunner()->RunsTasksInCurrentSequence());
#if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
fd_controllers_.clear();
#endif // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
}
void PerfettoTaskRunner::PostTask(std::function<void()> task) {
PostDelayedTask(task, /* delay_ms */ 0);
}
void PerfettoTaskRunner::PostDelayedTask(std::function<void()> task,
uint32_t delay_ms) {
base::ScopedDeferTaskPosting::PostOrDefer(
GetOrCreateTaskRunner(), FROM_HERE,
base::BindOnce(
[](std::function<void()> task) {
// We block any trace events that happens while any
// Perfetto task is running, or we'll get deadlocks in
// situations where the StartupTraceWriterRegistry tries
// to bind a writer which in turn causes a PostTask where
// a trace event can be emitted, which then deadlocks as
// it needs a new chunk from the same StartupTraceWriter
// which we're trying to bind and are keeping the lock
// to.
// TODO(oysteine): Try to see if we can be more selective
// about this.
const AutoReset<bool> resetter(GetThreadIsInTraceEvent(), true,
false);
task();
},
task),
base::Milliseconds(delay_ms));
}
bool PerfettoTaskRunner::RunsTasksOnCurrentThread() const {
DCHECK(task_runner_);
return task_runner_->RunsTasksInCurrentSequence();
}
// PlatformHandle is an int on POSIX, a HANDLE on Windows.
void PerfettoTaskRunner::AddFileDescriptorWatch(
perfetto::base::PlatformHandle fd,
std::function<void()> callback) {
#if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
DCHECK(GetOrCreateTaskRunner()->RunsTasksInCurrentSequence());
DCHECK(!base::Contains(fd_controllers_, fd));
// Set up the |fd| in the map to signal intent to add a watch. We need to
// PostTask the WatchReadable creation because if we do it in this task we'll
// race with perfetto setting up the connection on this task and the IO thread
// setting up epoll on the |fd|. Using a CancelableOnceClosure ensures that
// the |fd| won't be added for watch if RemoveFileDescriptorWatch is called.
fd_controllers_[fd].callback.Reset(
base::BindOnce(
[](PerfettoTaskRunner* perfetto_runner, int fd,
std::function<void()> callback) {
DCHECK(perfetto_runner->GetOrCreateTaskRunner()
->RunsTasksInCurrentSequence());
// When this callback runs, we must not have removed |fd|'s watch.
CHECK(base::Contains(perfetto_runner->fd_controllers_, fd));
auto& controller_and_cb = perfetto_runner->fd_controllers_[fd];
// We should never overwrite an existing watch.
CHECK(!controller_and_cb.controller);
controller_and_cb.controller =
base::FileDescriptorWatcher::WatchReadable(
fd, base::BindRepeating(
[](std::function<void()> callback) { callback(); },
std::move(callback)));
},
base::Unretained(this), fd, std::move(callback)));
task_runner_->PostTask(FROM_HERE, fd_controllers_[fd].callback.callback());
#else // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
NOTREACHED();
#endif // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
}
void PerfettoTaskRunner::RemoveFileDescriptorWatch(
perfetto::base::PlatformHandle fd) {
#if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
DCHECK(GetOrCreateTaskRunner()->RunsTasksInCurrentSequence());
DCHECK(base::Contains(fd_controllers_, fd));
// This also cancels the base::FileDescriptorWatcher::WatchReadable() task if
// it's pending.
fd_controllers_.erase(fd);
#else // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
NOTREACHED();
#endif // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
}
void PerfettoTaskRunner::ResetTaskRunnerForTesting(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
task_runner_ = std::move(task_runner);
}
void PerfettoTaskRunner::SetTaskRunner(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
DCHECK(!task_runner_);
task_runner_ = std::move(task_runner);
}
scoped_refptr<base::SequencedTaskRunner>
PerfettoTaskRunner::GetOrCreateTaskRunner() {
// TODO(eseckler): This is not really thread-safe. We should probably add a
// lock around this. At the moment we can get away without one because this
// method is called for the first time on the process's main thread before the
// tracing service connects.
if (!task_runner_) {
DCHECK(base::ThreadPoolInstance::Get());
task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_BLOCKING});
}
return task_runner_;
}
#if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
PerfettoTaskRunner::FDControllerAndCallback::FDControllerAndCallback() =
default;
PerfettoTaskRunner::FDControllerAndCallback::~FDControllerAndCallback() =
default;
#endif // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
} // namespace tracing
} // namespace base
|