• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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