// 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/logging.h" #include "src/base/platform/platform.h" #include "src/base/platform/time.h" #include "src/base/sys-info.h" #include "src/libplatform/worker-thread.h" namespace v8 { namespace platform { v8::Platform* CreateDefaultPlatform(int thread_pool_size) { DefaultPlatform* platform = new DefaultPlatform(); platform->SetThreadPoolSize(thread_pool_size); platform->EnsureInitialized(); return platform; } bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate) { return reinterpret_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate); } void SetTracingController( v8::Platform* platform, v8::platform::tracing::TracingController* tracing_controller) { return reinterpret_cast<DefaultPlatform*>(platform)->SetTracingController( tracing_controller); } const int DefaultPlatform::kMaxThreadPoolSize = 8; DefaultPlatform::DefaultPlatform() : initialized_(false), thread_pool_size_(0) {} DefaultPlatform::~DefaultPlatform() { if (tracing_controller_) { tracing_controller_->StopTracing(); tracing_controller_.reset(); } base::LockGuard<base::Mutex> guard(&lock_); queue_.Terminate(); if (initialized_) { for (auto i = thread_pool_.begin(); i != thread_pool_.end(); ++i) { delete *i; } } for (auto i = main_thread_queue_.begin(); i != main_thread_queue_.end(); ++i) { while (!i->second.empty()) { delete i->second.front(); i->second.pop(); } } for (auto i = main_thread_delayed_queue_.begin(); i != main_thread_delayed_queue_.end(); ++i) { while (!i->second.empty()) { delete i->second.top().second; i->second.pop(); } } } void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) { base::LockGuard<base::Mutex> guard(&lock_); DCHECK(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::EnsureInitialized() { base::LockGuard<base::Mutex> guard(&lock_); if (initialized_) return; initialized_ = true; for (int i = 0; i < thread_pool_size_; ++i) thread_pool_.push_back(new WorkerThread(&queue_)); } Task* DefaultPlatform::PopTaskInMainThreadQueue(v8::Isolate* isolate) { auto it = main_thread_queue_.find(isolate); if (it == main_thread_queue_.end() || it->second.empty()) { return NULL; } Task* task = it->second.front(); it->second.pop(); return task; } Task* DefaultPlatform::PopTaskInMainThreadDelayedQueue(v8::Isolate* isolate) { auto it = main_thread_delayed_queue_.find(isolate); if (it == main_thread_delayed_queue_.end() || it->second.empty()) { return NULL; } double now = MonotonicallyIncreasingTime(); std::pair<double, Task*> deadline_and_task = it->second.top(); if (deadline_and_task.first > now) { return NULL; } it->second.pop(); return deadline_and_task.second; } bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate) { Task* task = NULL; { base::LockGuard<base::Mutex> guard(&lock_); // Move delayed tasks that hit their deadline to the main queue. task = PopTaskInMainThreadDelayedQueue(isolate); while (task != NULL) { main_thread_queue_[isolate].push(task); task = PopTaskInMainThreadDelayedQueue(isolate); } task = PopTaskInMainThreadQueue(isolate); if (task == NULL) { return false; } } task->Run(); delete task; return true; } void DefaultPlatform::CallOnBackgroundThread(Task *task, ExpectedRuntime expected_runtime) { EnsureInitialized(); queue_.Append(task); } void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) { base::LockGuard<base::Mutex> guard(&lock_); main_thread_queue_[isolate].push(task); } void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate, Task* task, double delay_in_seconds) { base::LockGuard<base::Mutex> guard(&lock_); double deadline = MonotonicallyIncreasingTime() + delay_in_seconds; main_thread_delayed_queue_[isolate].push(std::make_pair(deadline, task)); } void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate, IdleTask* task) { UNREACHABLE(); } bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) { return false; } double DefaultPlatform::MonotonicallyIncreasingTime() { return base::TimeTicks::HighResolutionNow().ToInternalValue() / static_cast<double>(base::Time::kMicrosecondsPerSecond); } uint64_t DefaultPlatform::AddTraceEvent( char phase, const uint8_t* category_enabled_flag, const char* name, const char* scope, uint64_t id, uint64_t bind_id, int num_args, const char** arg_names, const uint8_t* arg_types, const uint64_t* arg_values, std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables, unsigned int flags) { if (tracing_controller_) { return tracing_controller_->AddTraceEvent( phase, category_enabled_flag, name, scope, id, bind_id, num_args, arg_names, arg_types, arg_values, arg_convertables, flags); } return 0; } void DefaultPlatform::UpdateTraceEventDuration( const uint8_t* category_enabled_flag, const char* name, uint64_t handle) { if (tracing_controller_) { tracing_controller_->UpdateTraceEventDuration(category_enabled_flag, name, handle); } } const uint8_t* DefaultPlatform::GetCategoryGroupEnabled(const char* name) { if (tracing_controller_) { return tracing_controller_->GetCategoryGroupEnabled(name); } static uint8_t no = 0; return &no; } const char* DefaultPlatform::GetCategoryGroupName( const uint8_t* category_enabled_flag) { static const char dummy[] = "dummy"; return dummy; } void DefaultPlatform::SetTracingController( tracing::TracingController* tracing_controller) { tracing_controller_.reset(tracing_controller); } size_t DefaultPlatform::NumberOfAvailableBackgroundThreads() { return static_cast<size_t>(thread_pool_size_); } void DefaultPlatform::AddTraceStateObserver(TraceStateObserver* observer) { if (!tracing_controller_) return; tracing_controller_->AddTraceStateObserver(observer); } void DefaultPlatform::RemoveTraceStateObserver(TraceStateObserver* observer) { if (!tracing_controller_) return; tracing_controller_->RemoveTraceStateObserver(observer); } } // namespace platform } // namespace v8