aa7c6e22f9
Reuse the existing builtin and extension infrastructure to provide a garbage collection mechanism that allows for asynchronous execution. On --expose-gc, this changes the gc call to parse parameters the following: (1) Parse options when encountering an options object with known properties. (2) No parameters is parsed as {type: 'major', execution: 'sync'}. (3) Truthy parameter that is not setting options is parsed as {type: 'minor', execution: 'sync'}. (2) and (3) preserve backwards compatibility for existing callers as this may be used widely across various test and benchmarking infrastructures. Valid options: - type: 'major' or 'minor' for full GC and Scavenge, respectively. - execution: 'sync' or 'async' for synchronous and asynchronous execution respectively. Returns a Promise that resolves when GC is done when asynchronous execution is requested, and undefined otherwise. Note: This is implemented as builtin to avoid having any stack at all. This information is also passed to the embedder to allow skipping stack scanning. Change-Id: Ie5c9b6f0d55238abfeb9051ffa1837501d474934 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1793143 Commit-Queue: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#63659}
130 lines
4.3 KiB
C++
130 lines
4.3 KiB
C++
// 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::MutexGuard 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::MutexGuard&) {
|
|
if (terminated_) return;
|
|
task_queue_.push(std::move(task));
|
|
event_loop_control_.NotifyOne();
|
|
}
|
|
|
|
void DefaultForegroundTaskRunner::PostTask(std::unique_ptr<Task> task) {
|
|
base::MutexGuard 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::MutexGuard 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::MutexGuard guard(&lock_);
|
|
if (terminated_) return;
|
|
idle_task_queue_.push(std::move(task));
|
|
}
|
|
|
|
bool DefaultForegroundTaskRunner::IdleTasksEnabled() {
|
|
return idle_task_support_ == IdleTaskSupport::kEnabled;
|
|
}
|
|
|
|
void DefaultForegroundTaskRunner::PostNonNestableTask(
|
|
std::unique_ptr<Task> task) {
|
|
// Default platform does not nest tasks.
|
|
PostTask(std::move(task));
|
|
}
|
|
|
|
bool DefaultForegroundTaskRunner::NonNestableTasksEnabled() const {
|
|
return true;
|
|
}
|
|
|
|
std::unique_ptr<Task> DefaultForegroundTaskRunner::PopTaskFromQueue(
|
|
MessageLoopBehavior wait_for_work) {
|
|
base::MutexGuard 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::MutexGuard&) {
|
|
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::MutexGuard 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::MutexGuard&) {
|
|
event_loop_control_.Wait(&lock_);
|
|
}
|
|
|
|
} // namespace platform
|
|
} // namespace v8
|