1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/libplatform/default-platform.h"
6
7 #include <algorithm>
8 #include <queue>
9
10 #include "include/libplatform/libplatform.h"
11 #include "src/base/debug/stack_trace.h"
12 #include "src/base/logging.h"
13 #include "src/base/page-allocator.h"
14 #include "src/base/platform/platform.h"
15 #include "src/base/platform/time.h"
16 #include "src/base/sys-info.h"
17 #include "src/libplatform/default-foreground-task-runner.h"
18 #include "src/libplatform/default-worker-threads-task-runner.h"
19
20 namespace v8 {
21 namespace platform {
22
23 namespace {
24
PrintStackTrace()25 void PrintStackTrace() {
26 v8::base::debug::StackTrace trace;
27 trace.Print();
28 // Avoid dumping duplicate stack trace on abort signal.
29 v8::base::debug::DisableSignalStackDump();
30 }
31
32 } // namespace
33
NewDefaultPlatform(int thread_pool_size,IdleTaskSupport idle_task_support,InProcessStackDumping in_process_stack_dumping,std::unique_ptr<v8::TracingController> tracing_controller)34 std::unique_ptr<v8::Platform> NewDefaultPlatform(
35 int thread_pool_size, IdleTaskSupport idle_task_support,
36 InProcessStackDumping in_process_stack_dumping,
37 std::unique_ptr<v8::TracingController> tracing_controller) {
38 if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
39 v8::base::debug::EnableInProcessStackDumping();
40 }
41 std::unique_ptr<DefaultPlatform> platform(
42 new DefaultPlatform(idle_task_support, std::move(tracing_controller)));
43 platform->SetThreadPoolSize(thread_pool_size);
44 platform->EnsureBackgroundTaskRunnerInitialized();
45 return std::move(platform);
46 }
47
CreateDefaultPlatform(int thread_pool_size,IdleTaskSupport idle_task_support,InProcessStackDumping in_process_stack_dumping,v8::TracingController * tracing_controller)48 v8::Platform* CreateDefaultPlatform(
49 int thread_pool_size, IdleTaskSupport idle_task_support,
50 InProcessStackDumping in_process_stack_dumping,
51 v8::TracingController* tracing_controller) {
52 return NewDefaultPlatform(
53 thread_pool_size, idle_task_support, in_process_stack_dumping,
54 std::unique_ptr<v8::TracingController>(tracing_controller))
55 .release();
56 }
57
PumpMessageLoop(v8::Platform * platform,v8::Isolate * isolate,MessageLoopBehavior behavior)58 bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate,
59 MessageLoopBehavior behavior) {
60 return static_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate,
61 behavior);
62 }
63
RunIdleTasks(v8::Platform * platform,v8::Isolate * isolate,double idle_time_in_seconds)64 void RunIdleTasks(v8::Platform* platform, v8::Isolate* isolate,
65 double idle_time_in_seconds) {
66 static_cast<DefaultPlatform*>(platform)->RunIdleTasks(isolate,
67 idle_time_in_seconds);
68 }
69
SetTracingController(v8::Platform * platform,v8::platform::tracing::TracingController * tracing_controller)70 void SetTracingController(
71 v8::Platform* platform,
72 v8::platform::tracing::TracingController* tracing_controller) {
73 static_cast<DefaultPlatform*>(platform)->SetTracingController(
74 std::unique_ptr<v8::TracingController>(tracing_controller));
75 }
76
77 const int DefaultPlatform::kMaxThreadPoolSize = 8;
78
DefaultPlatform(IdleTaskSupport idle_task_support,std::unique_ptr<v8::TracingController> tracing_controller)79 DefaultPlatform::DefaultPlatform(
80 IdleTaskSupport idle_task_support,
81 std::unique_ptr<v8::TracingController> tracing_controller)
82 : thread_pool_size_(0),
83 idle_task_support_(idle_task_support),
84 tracing_controller_(std::move(tracing_controller)),
85 page_allocator_(new v8::base::PageAllocator()),
86 time_function_for_testing_(nullptr) {
87 if (!tracing_controller_) {
88 tracing::TracingController* controller = new tracing::TracingController();
89 controller->Initialize(nullptr);
90 tracing_controller_.reset(controller);
91 }
92 }
93
~DefaultPlatform()94 DefaultPlatform::~DefaultPlatform() {
95 base::LockGuard<base::Mutex> guard(&lock_);
96 if (worker_threads_task_runner_) worker_threads_task_runner_->Terminate();
97 for (auto it : foreground_task_runner_map_) {
98 it.second->Terminate();
99 }
100 }
101
SetThreadPoolSize(int thread_pool_size)102 void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) {
103 base::LockGuard<base::Mutex> guard(&lock_);
104 DCHECK_GE(thread_pool_size, 0);
105 if (thread_pool_size < 1) {
106 thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
107 }
108 thread_pool_size_ =
109 std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
110 }
111
EnsureBackgroundTaskRunnerInitialized()112 void DefaultPlatform::EnsureBackgroundTaskRunnerInitialized() {
113 base::LockGuard<base::Mutex> guard(&lock_);
114 if (!worker_threads_task_runner_) {
115 worker_threads_task_runner_ =
116 std::make_shared<DefaultWorkerThreadsTaskRunner>(thread_pool_size_);
117 }
118 }
119
120 namespace {
121
DefaultTimeFunction()122 double DefaultTimeFunction() {
123 return base::TimeTicks::HighResolutionNow().ToInternalValue() /
124 static_cast<double>(base::Time::kMicrosecondsPerSecond);
125 }
126
127 } // namespace
128
SetTimeFunctionForTesting(DefaultPlatform::TimeFunction time_function)129 void DefaultPlatform::SetTimeFunctionForTesting(
130 DefaultPlatform::TimeFunction time_function) {
131 base::LockGuard<base::Mutex> guard(&lock_);
132 time_function_for_testing_ = time_function;
133 // The time function has to be right after the construction of the platform.
134 DCHECK(foreground_task_runner_map_.empty());
135 }
136
PumpMessageLoop(v8::Isolate * isolate,MessageLoopBehavior wait_for_work)137 bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate,
138 MessageLoopBehavior wait_for_work) {
139 bool failed_result = wait_for_work == MessageLoopBehavior::kWaitForWork;
140 std::shared_ptr<DefaultForegroundTaskRunner> task_runner;
141 {
142 base::LockGuard<base::Mutex> guard(&lock_);
143 if (foreground_task_runner_map_.find(isolate) ==
144 foreground_task_runner_map_.end()) {
145 return failed_result;
146 }
147 task_runner = foreground_task_runner_map_[isolate];
148 }
149
150 std::unique_ptr<Task> task = task_runner->PopTaskFromQueue(wait_for_work);
151 if (!task) return failed_result;
152
153 task->Run();
154 return true;
155 }
156
RunIdleTasks(v8::Isolate * isolate,double idle_time_in_seconds)157 void DefaultPlatform::RunIdleTasks(v8::Isolate* isolate,
158 double idle_time_in_seconds) {
159 DCHECK_EQ(IdleTaskSupport::kEnabled, idle_task_support_);
160 std::shared_ptr<DefaultForegroundTaskRunner> task_runner;
161 {
162 base::LockGuard<base::Mutex> guard(&lock_);
163 if (foreground_task_runner_map_.find(isolate) ==
164 foreground_task_runner_map_.end()) {
165 return;
166 }
167 task_runner = foreground_task_runner_map_[isolate];
168 }
169 double deadline_in_seconds =
170 MonotonicallyIncreasingTime() + idle_time_in_seconds;
171
172 while (deadline_in_seconds > MonotonicallyIncreasingTime()) {
173 std::unique_ptr<IdleTask> task = task_runner->PopTaskFromIdleQueue();
174 if (!task) return;
175 task->Run(deadline_in_seconds);
176 }
177 }
178
GetForegroundTaskRunner(v8::Isolate * isolate)179 std::shared_ptr<TaskRunner> DefaultPlatform::GetForegroundTaskRunner(
180 v8::Isolate* isolate) {
181 base::LockGuard<base::Mutex> guard(&lock_);
182 if (foreground_task_runner_map_.find(isolate) ==
183 foreground_task_runner_map_.end()) {
184 foreground_task_runner_map_.insert(std::make_pair(
185 isolate, std::make_shared<DefaultForegroundTaskRunner>(
186 idle_task_support_, time_function_for_testing_
187 ? time_function_for_testing_
188 : DefaultTimeFunction)));
189 }
190 return foreground_task_runner_map_[isolate];
191 }
192
CallOnWorkerThread(std::unique_ptr<Task> task)193 void DefaultPlatform::CallOnWorkerThread(std::unique_ptr<Task> task) {
194 EnsureBackgroundTaskRunnerInitialized();
195 worker_threads_task_runner_->PostTask(std::move(task));
196 }
197
CallDelayedOnWorkerThread(std::unique_ptr<Task> task,double delay_in_seconds)198 void DefaultPlatform::CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
199 double delay_in_seconds) {
200 EnsureBackgroundTaskRunnerInitialized();
201 worker_threads_task_runner_->PostDelayedTask(std::move(task),
202 delay_in_seconds);
203 }
204
CallOnForegroundThread(v8::Isolate * isolate,Task * task)205 void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
206 GetForegroundTaskRunner(isolate)->PostTask(std::unique_ptr<Task>(task));
207 }
208
CallDelayedOnForegroundThread(Isolate * isolate,Task * task,double delay_in_seconds)209 void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate,
210 Task* task,
211 double delay_in_seconds) {
212 GetForegroundTaskRunner(isolate)->PostDelayedTask(std::unique_ptr<Task>(task),
213 delay_in_seconds);
214 }
215
CallIdleOnForegroundThread(Isolate * isolate,IdleTask * task)216 void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate,
217 IdleTask* task) {
218 GetForegroundTaskRunner(isolate)->PostIdleTask(
219 std::unique_ptr<IdleTask>(task));
220 }
221
IdleTasksEnabled(Isolate * isolate)222 bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) {
223 return idle_task_support_ == IdleTaskSupport::kEnabled;
224 }
225
MonotonicallyIncreasingTime()226 double DefaultPlatform::MonotonicallyIncreasingTime() {
227 if (time_function_for_testing_) return time_function_for_testing_();
228 return DefaultTimeFunction();
229 }
230
CurrentClockTimeMillis()231 double DefaultPlatform::CurrentClockTimeMillis() {
232 return base::OS::TimeCurrentMillis();
233 }
234
GetTracingController()235 TracingController* DefaultPlatform::GetTracingController() {
236 return tracing_controller_.get();
237 }
238
SetTracingController(std::unique_ptr<v8::TracingController> tracing_controller)239 void DefaultPlatform::SetTracingController(
240 std::unique_ptr<v8::TracingController> tracing_controller) {
241 DCHECK_NOT_NULL(tracing_controller.get());
242 tracing_controller_ = std::move(tracing_controller);
243 }
244
NumberOfWorkerThreads()245 int DefaultPlatform::NumberOfWorkerThreads() { return thread_pool_size_; }
246
GetStackTracePrinter()247 Platform::StackTracePrinter DefaultPlatform::GetStackTracePrinter() {
248 return PrintStackTrace;
249 }
250
GetPageAllocator()251 v8::PageAllocator* DefaultPlatform::GetPageAllocator() {
252 return page_allocator_.get();
253 }
254
255 } // namespace platform
256 } // namespace v8
257