blob: 656bff66466b3771691f56d6ffeecb87de595502 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/inspector/inspector_task_runner.h"
#include "third_party/blink/renderer/core/inspector/thread_debugger.h"
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
namespace blink {
InspectorTaskRunner::IgnoreInterruptsScope::IgnoreInterruptsScope(
scoped_refptr<InspectorTaskRunner> task_runner)
: was_ignoring_(task_runner->ignore_interrupts_),
task_runner_(task_runner) {
// There may be nested scopes e.g. when tasks are being executed on XHR
// breakpoint.
task_runner_->ignore_interrupts_ = true;
}
InspectorTaskRunner::IgnoreInterruptsScope::~IgnoreInterruptsScope() {
task_runner_->ignore_interrupts_ = was_ignoring_;
}
InspectorTaskRunner::InspectorTaskRunner(
scoped_refptr<base::SingleThreadTaskRunner> isolate_task_runner)
: isolate_task_runner_(isolate_task_runner), condition_(mutex_) {}
InspectorTaskRunner::~InspectorTaskRunner() = default;
void InspectorTaskRunner::InitIsolate(v8::Isolate* isolate) {
MutexLocker lock(mutex_);
isolate_ = isolate;
}
void InspectorTaskRunner::Dispose() {
MutexLocker lock(mutex_);
disposed_ = true;
isolate_ = nullptr;
isolate_task_runner_ = nullptr;
condition_.Broadcast();
}
void InspectorTaskRunner::AppendTask(Task task) {
MutexLocker lock(mutex_);
if (disposed_)
return;
queue_.push_back(std::move(task));
condition_.Signal();
PostCrossThreadTask(
*isolate_task_runner_, FROM_HERE,
CrossThreadBind(&InspectorTaskRunner::PerformSingleTaskDontWait,
WrapRefCounted(this)));
if (isolate_)
isolate_->RequestInterrupt(&V8InterruptCallback, this);
}
bool InspectorTaskRunner::WaitForAndRunSingleTask() {
// |isolate_task_runner_| might be null in unit tests.
DCHECK(!isolate_task_runner_ ||
isolate_task_runner_->BelongsToCurrentThread());
{
MutexLocker lock(mutex_);
if (isolate_)
ThreadDebugger::IdleStarted(isolate_);
}
Task task = TakeNextTask(kWaitForTask);
{
MutexLocker lock(mutex_);
if (isolate_)
ThreadDebugger::IdleFinished(isolate_);
}
if (!task)
return false;
PerformSingleTask(std::move(task));
return true;
}
bool InspectorTaskRunner::IsRunningTask() {
MutexLocker lock(mutex_);
return running_task_;
}
InspectorTaskRunner::Task InspectorTaskRunner::TakeNextTask(
InspectorTaskRunner::WaitMode wait_mode) {
MutexLocker lock(mutex_);
if (wait_mode == kWaitForTask) {
while (!disposed_ && queue_.IsEmpty())
condition_.Wait();
}
if (disposed_ || queue_.IsEmpty())
return Task();
return queue_.TakeFirst();
}
void InspectorTaskRunner::PerformSingleTask(Task task) {
DCHECK(isolate_task_runner_->BelongsToCurrentThread());
IgnoreInterruptsScope scope(this);
{
MutexLocker lock(mutex_);
DCHECK(!running_task_);
running_task_ = true;
}
std::move(task).Run();
{
MutexLocker lock(mutex_);
running_task_ = false;
}
}
void InspectorTaskRunner::PerformSingleTaskDontWait() {
Task task = TakeNextTask(kDontWaitForTask);
if (task) {
DCHECK(isolate_task_runner_->BelongsToCurrentThread());
PerformSingleTask(std::move(task));
}
}
void InspectorTaskRunner::V8InterruptCallback(v8::Isolate*, void* data) {
InspectorTaskRunner* runner = static_cast<InspectorTaskRunner*>(data);
if (runner->ignore_interrupts_)
return;
while (true) {
Task task = runner->TakeNextTask(kDontWaitForTask);
if (!task)
return;
runner->PerformSingleTask(std::move(task));
}
}
} // namespace blink