#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"
namespace base::tracing {
PerfettoTaskRunner::PerfettoTaskRunner(
scoped_refptr<base::SequencedTaskRunner> task_runner,
bool defer_delayed_tasks)
: task_runner_(std::move(task_runner)),
defer_delayed_tasks_(defer_delayed_tasks) {
CHECK(task_runner_);
}
PerfettoTaskRunner::~PerfettoTaskRunner() {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
fd_controllers_.clear();
#endif
}
void PerfettoTaskRunner::PostTask(std::function<void()> task) {
PostDelayedTask(task, 0);
}
void PerfettoTaskRunner::PostDelayedTask(std::function<void()> task,
uint32_t delay_ms) {
if (defer_delayed_tasks_ && delay_ms) {
deferred_delayed_tasks_.emplace_back(task, delay_ms);
return;
}
base::ScopedDeferTaskPosting::PostOrDefer(
task_runner_, FROM_HERE,
base::BindOnce(
[](std::function<void()> task) {
const AutoReset<bool> resetter(GetThreadIsInTraceEvent(), true,
false);
task();
},
task),
base::Milliseconds(delay_ms));
}
bool PerfettoTaskRunner::RunsTasksOnCurrentThread() const {
DCHECK(task_runner_);
return task_runner_->RunsTasksInCurrentSequence();
}
void PerfettoTaskRunner::AddFileDescriptorWatch(
perfetto::base::PlatformHandle fd,
std::function<void()> callback) {
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
DCHECK(task_runner_->RunsTasksInCurrentSequence());
DCHECK(!base::Contains(fd_controllers_, fd));
fd_controllers_[fd].callback.Reset(base::BindOnce(
[](PerfettoTaskRunner* perfetto_runner, int fd,
std::function<void()> callback) {
DCHECK(perfetto_runner->task_runner_->RunsTasksInCurrentSequence());
CHECK(base::Contains(perfetto_runner->fd_controllers_, fd));
auto& controller_and_cb = perfetto_runner->fd_controllers_[fd];
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
NOTREACHED();
#endif
}
void PerfettoTaskRunner::RemoveFileDescriptorWatch(
perfetto::base::PlatformHandle fd) {
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
DCHECK(task_runner_->RunsTasksInCurrentSequence());
DCHECK(base::Contains(fd_controllers_, fd));
fd_controllers_.erase(fd);
#else
NOTREACHED();
#endif
}
void PerfettoTaskRunner::ResetTaskRunner(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
task_runner_ = std::move(task_runner);
defer_delayed_tasks_ = false;
for (auto& task : deferred_delayed_tasks_) {
PostDelayedTask(task.task, task.delay);
}
deferred_delayed_tasks_.clear();
}
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
PerfettoTaskRunner::FDControllerAndCallback::FDControllerAndCallback() =
default;
PerfettoTaskRunner::FDControllerAndCallback::~FDControllerAndCallback() =
default;
#endif
PerfettoTaskRunner::DeferredTask::DeferredTask(std::function<void()> task,
uint32_t delay)
: task(std::move(task)), delay(delay) {}
PerfettoTaskRunner::DeferredTask::DeferredTask(DeferredTask&& task) = default;
PerfettoTaskRunner::DeferredTask::~DeferredTask() = default;
}