// Copyright 2013 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-platform.h"
|
|
#include <algorithm>
|
#include <queue>
|
|
#include "include/libplatform/libplatform.h"
|
#include "src/base/debug/stack_trace.h"
|
#include "src/base/logging.h"
|
#include "src/base/page-allocator.h"
|
#include "src/base/platform/platform.h"
|
#include "src/base/platform/time.h"
|
#include "src/base/sys-info.h"
|
#include "src/libplatform/default-foreground-task-runner.h"
|
#include "src/libplatform/default-worker-threads-task-runner.h"
|
|
namespace v8 {
|
namespace platform {
|
|
namespace {
|
|
void PrintStackTrace() {
|
v8::base::debug::StackTrace trace;
|
trace.Print();
|
// Avoid dumping duplicate stack trace on abort signal.
|
v8::base::debug::DisableSignalStackDump();
|
}
|
|
} // namespace
|
|
std::unique_ptr<v8::Platform> NewDefaultPlatform(
|
int thread_pool_size, IdleTaskSupport idle_task_support,
|
InProcessStackDumping in_process_stack_dumping,
|
std::unique_ptr<v8::TracingController> tracing_controller) {
|
if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
|
v8::base::debug::EnableInProcessStackDumping();
|
}
|
std::unique_ptr<DefaultPlatform> platform(
|
new DefaultPlatform(idle_task_support, std::move(tracing_controller)));
|
platform->SetThreadPoolSize(thread_pool_size);
|
platform->EnsureBackgroundTaskRunnerInitialized();
|
return std::move(platform);
|
}
|
|
v8::Platform* CreateDefaultPlatform(
|
int thread_pool_size, IdleTaskSupport idle_task_support,
|
InProcessStackDumping in_process_stack_dumping,
|
v8::TracingController* tracing_controller) {
|
return NewDefaultPlatform(
|
thread_pool_size, idle_task_support, in_process_stack_dumping,
|
std::unique_ptr<v8::TracingController>(tracing_controller))
|
.release();
|
}
|
|
bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate,
|
MessageLoopBehavior behavior) {
|
return static_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate,
|
behavior);
|
}
|
|
void RunIdleTasks(v8::Platform* platform, v8::Isolate* isolate,
|
double idle_time_in_seconds) {
|
static_cast<DefaultPlatform*>(platform)->RunIdleTasks(isolate,
|
idle_time_in_seconds);
|
}
|
|
void SetTracingController(
|
v8::Platform* platform,
|
v8::platform::tracing::TracingController* tracing_controller) {
|
static_cast<DefaultPlatform*>(platform)->SetTracingController(
|
std::unique_ptr<v8::TracingController>(tracing_controller));
|
}
|
|
const int DefaultPlatform::kMaxThreadPoolSize = 8;
|
|
DefaultPlatform::DefaultPlatform(
|
IdleTaskSupport idle_task_support,
|
std::unique_ptr<v8::TracingController> tracing_controller)
|
: thread_pool_size_(0),
|
idle_task_support_(idle_task_support),
|
tracing_controller_(std::move(tracing_controller)),
|
page_allocator_(new v8::base::PageAllocator()),
|
time_function_for_testing_(nullptr) {
|
if (!tracing_controller_) {
|
tracing::TracingController* controller = new tracing::TracingController();
|
controller->Initialize(nullptr);
|
tracing_controller_.reset(controller);
|
}
|
}
|
|
DefaultPlatform::~DefaultPlatform() {
|
base::LockGuard<base::Mutex> guard(&lock_);
|
if (worker_threads_task_runner_) worker_threads_task_runner_->Terminate();
|
for (auto it : foreground_task_runner_map_) {
|
it.second->Terminate();
|
}
|
}
|
|
void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) {
|
base::LockGuard<base::Mutex> guard(&lock_);
|
DCHECK_GE(thread_pool_size, 0);
|
if (thread_pool_size < 1) {
|
thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
|
}
|
thread_pool_size_ =
|
std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
|
}
|
|
void DefaultPlatform::EnsureBackgroundTaskRunnerInitialized() {
|
base::LockGuard<base::Mutex> guard(&lock_);
|
if (!worker_threads_task_runner_) {
|
worker_threads_task_runner_ =
|
std::make_shared<DefaultWorkerThreadsTaskRunner>(thread_pool_size_);
|
}
|
}
|
|
namespace {
|
|
double DefaultTimeFunction() {
|
return base::TimeTicks::HighResolutionNow().ToInternalValue() /
|
static_cast<double>(base::Time::kMicrosecondsPerSecond);
|
}
|
|
} // namespace
|
|
void DefaultPlatform::SetTimeFunctionForTesting(
|
DefaultPlatform::TimeFunction time_function) {
|
base::LockGuard<base::Mutex> guard(&lock_);
|
time_function_for_testing_ = time_function;
|
// The time function has to be right after the construction of the platform.
|
DCHECK(foreground_task_runner_map_.empty());
|
}
|
|
bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate,
|
MessageLoopBehavior wait_for_work) {
|
bool failed_result = wait_for_work == MessageLoopBehavior::kWaitForWork;
|
std::shared_ptr<DefaultForegroundTaskRunner> task_runner;
|
{
|
base::LockGuard<base::Mutex> guard(&lock_);
|
if (foreground_task_runner_map_.find(isolate) ==
|
foreground_task_runner_map_.end()) {
|
return failed_result;
|
}
|
task_runner = foreground_task_runner_map_[isolate];
|
}
|
|
std::unique_ptr<Task> task = task_runner->PopTaskFromQueue(wait_for_work);
|
if (!task) return failed_result;
|
|
task->Run();
|
return true;
|
}
|
|
void DefaultPlatform::RunIdleTasks(v8::Isolate* isolate,
|
double idle_time_in_seconds) {
|
DCHECK_EQ(IdleTaskSupport::kEnabled, idle_task_support_);
|
std::shared_ptr<DefaultForegroundTaskRunner> task_runner;
|
{
|
base::LockGuard<base::Mutex> guard(&lock_);
|
if (foreground_task_runner_map_.find(isolate) ==
|
foreground_task_runner_map_.end()) {
|
return;
|
}
|
task_runner = foreground_task_runner_map_[isolate];
|
}
|
double deadline_in_seconds =
|
MonotonicallyIncreasingTime() + idle_time_in_seconds;
|
|
while (deadline_in_seconds > MonotonicallyIncreasingTime()) {
|
std::unique_ptr<IdleTask> task = task_runner->PopTaskFromIdleQueue();
|
if (!task) return;
|
task->Run(deadline_in_seconds);
|
}
|
}
|
|
std::shared_ptr<TaskRunner> DefaultPlatform::GetForegroundTaskRunner(
|
v8::Isolate* isolate) {
|
base::LockGuard<base::Mutex> guard(&lock_);
|
if (foreground_task_runner_map_.find(isolate) ==
|
foreground_task_runner_map_.end()) {
|
foreground_task_runner_map_.insert(std::make_pair(
|
isolate, std::make_shared<DefaultForegroundTaskRunner>(
|
idle_task_support_, time_function_for_testing_
|
? time_function_for_testing_
|
: DefaultTimeFunction)));
|
}
|
return foreground_task_runner_map_[isolate];
|
}
|
|
void DefaultPlatform::CallOnWorkerThread(std::unique_ptr<Task> task) {
|
EnsureBackgroundTaskRunnerInitialized();
|
worker_threads_task_runner_->PostTask(std::move(task));
|
}
|
|
void DefaultPlatform::CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
|
double delay_in_seconds) {
|
EnsureBackgroundTaskRunnerInitialized();
|
worker_threads_task_runner_->PostDelayedTask(std::move(task),
|
delay_in_seconds);
|
}
|
|
void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
|
GetForegroundTaskRunner(isolate)->PostTask(std::unique_ptr<Task>(task));
|
}
|
|
void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate,
|
Task* task,
|
double delay_in_seconds) {
|
GetForegroundTaskRunner(isolate)->PostDelayedTask(std::unique_ptr<Task>(task),
|
delay_in_seconds);
|
}
|
|
void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate,
|
IdleTask* task) {
|
GetForegroundTaskRunner(isolate)->PostIdleTask(
|
std::unique_ptr<IdleTask>(task));
|
}
|
|
bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) {
|
return idle_task_support_ == IdleTaskSupport::kEnabled;
|
}
|
|
double DefaultPlatform::MonotonicallyIncreasingTime() {
|
if (time_function_for_testing_) return time_function_for_testing_();
|
return DefaultTimeFunction();
|
}
|
|
double DefaultPlatform::CurrentClockTimeMillis() {
|
return base::OS::TimeCurrentMillis();
|
}
|
|
TracingController* DefaultPlatform::GetTracingController() {
|
return tracing_controller_.get();
|
}
|
|
void DefaultPlatform::SetTracingController(
|
std::unique_ptr<v8::TracingController> tracing_controller) {
|
DCHECK_NOT_NULL(tracing_controller.get());
|
tracing_controller_ = std::move(tracing_controller);
|
}
|
|
int DefaultPlatform::NumberOfWorkerThreads() { return thread_pool_size_; }
|
|
Platform::StackTracePrinter DefaultPlatform::GetStackTracePrinter() {
|
return PrintStackTrace;
|
}
|
|
v8::PageAllocator* DefaultPlatform::GetPageAllocator() {
|
return page_allocator_.get();
|
}
|
|
} // namespace platform
|
} // namespace v8
|