blob: 140dd404ec6eff87b70d4292040198c23544b537 [file] [log] [blame]
// Copyright 2017 the V8 project 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 "src/libplatform/default-foreground-task-runner.h"
#include "src/base/platform/mutex.h"
#include "src/libplatform/default-platform.h"
namespace v8 {
namespace platform {
DefaultForegroundTaskRunner::DefaultForegroundTaskRunner(
IdleTaskSupport idle_task_support, TimeFunction time_function)
: idle_task_support_(idle_task_support), time_function_(time_function) {}
void DefaultForegroundTaskRunner::Terminate() {
base::LockGuard<base::Mutex> guard(&lock_);
terminated_ = true;
// Drain the task queues.
while (!task_queue_.empty()) task_queue_.pop();
while (!delayed_task_queue_.empty()) delayed_task_queue_.pop();
while (!idle_task_queue_.empty()) idle_task_queue_.pop();
}
void DefaultForegroundTaskRunner::PostTaskLocked(
std::unique_ptr<Task> task, const base::LockGuard<base::Mutex>&) {
if (terminated_) return;
task_queue_.push(std::move(task));
event_loop_control_.NotifyOne();
}
void DefaultForegroundTaskRunner::PostTask(std::unique_ptr<Task> task) {
base::LockGuard<base::Mutex> guard(&lock_);
PostTaskLocked(std::move(task), guard);
}
double DefaultForegroundTaskRunner::MonotonicallyIncreasingTime() {
return time_function_();
}
void DefaultForegroundTaskRunner::PostDelayedTask(std::unique_ptr<Task> task,
double delay_in_seconds) {
DCHECK_GE(delay_in_seconds, 0.0);
base::LockGuard<base::Mutex> guard(&lock_);
if (terminated_) return;
double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
delayed_task_queue_.push(std::make_pair(deadline, std::move(task)));
}
void DefaultForegroundTaskRunner::PostIdleTask(std::unique_ptr<IdleTask> task) {
CHECK_EQ(IdleTaskSupport::kEnabled, idle_task_support_);
base::LockGuard<base::Mutex> guard(&lock_);
if (terminated_) return;
idle_task_queue_.push(std::move(task));
}
bool DefaultForegroundTaskRunner::IdleTasksEnabled() {
return idle_task_support_ == IdleTaskSupport::kEnabled;
}
std::unique_ptr<Task> DefaultForegroundTaskRunner::PopTaskFromQueue(
MessageLoopBehavior wait_for_work) {
base::LockGuard<base::Mutex> guard(&lock_);
// Move delayed tasks that hit their deadline to the main queue.
std::unique_ptr<Task> task = PopTaskFromDelayedQueueLocked(guard);
while (task) {
PostTaskLocked(std::move(task), guard);
task = PopTaskFromDelayedQueueLocked(guard);
}
while (task_queue_.empty()) {
if (wait_for_work == MessageLoopBehavior::kDoNotWait) return {};
WaitForTaskLocked(guard);
}
task = std::move(task_queue_.front());
task_queue_.pop();
return task;
}
std::unique_ptr<Task>
DefaultForegroundTaskRunner::PopTaskFromDelayedQueueLocked(
const base::LockGuard<base::Mutex>&) {
if (delayed_task_queue_.empty()) return {};
double now = MonotonicallyIncreasingTime();
const DelayedEntry& deadline_and_task = delayed_task_queue_.top();
if (deadline_and_task.first > now) return {};
// The const_cast here is necessary because there does not exist a clean way
// to get a unique_ptr out of the priority queue. We provide the priority
// queue with a custom comparison operator to make sure that the priority
// queue does not access the unique_ptr. Therefore it should be safe to reset
// the unique_ptr in the priority queue here. Note that the DelayedEntry is
// removed from the priority_queue immediately afterwards.
std::unique_ptr<Task> result =
std::move(const_cast<DelayedEntry&>(deadline_and_task).second);
delayed_task_queue_.pop();
return result;
}
std::unique_ptr<IdleTask> DefaultForegroundTaskRunner::PopTaskFromIdleQueue() {
base::LockGuard<base::Mutex> guard(&lock_);
if (idle_task_queue_.empty()) return {};
std::unique_ptr<IdleTask> task = std::move(idle_task_queue_.front());
idle_task_queue_.pop();
return task;
}
void DefaultForegroundTaskRunner::WaitForTaskLocked(
const base::LockGuard<base::Mutex>&) {
event_loop_control_.Wait(&lock_);
}
} // namespace platform
} // namespace v8