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/logging.h"
12 #include "src/base/platform/platform.h"
13 #include "src/base/platform/time.h"
14 #include "src/base/sys-info.h"
15 #include "src/libplatform/worker-thread.h"
16
17 namespace v8 {
18 namespace platform {
19
20
CreateDefaultPlatform(int thread_pool_size)21 v8::Platform* CreateDefaultPlatform(int thread_pool_size) {
22 DefaultPlatform* platform = new DefaultPlatform();
23 platform->SetThreadPoolSize(thread_pool_size);
24 platform->EnsureInitialized();
25 return platform;
26 }
27
28
PumpMessageLoop(v8::Platform * platform,v8::Isolate * isolate)29 bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate) {
30 return reinterpret_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate);
31 }
32
RunIdleTasks(v8::Platform * platform,v8::Isolate * isolate,double idle_time_in_seconds)33 void RunIdleTasks(v8::Platform* platform, v8::Isolate* isolate,
34 double idle_time_in_seconds) {
35 reinterpret_cast<DefaultPlatform*>(platform)->RunIdleTasks(
36 isolate, idle_time_in_seconds);
37 }
38
SetTracingController(v8::Platform * platform,v8::platform::tracing::TracingController * tracing_controller)39 void SetTracingController(
40 v8::Platform* platform,
41 v8::platform::tracing::TracingController* tracing_controller) {
42 return reinterpret_cast<DefaultPlatform*>(platform)->SetTracingController(
43 tracing_controller);
44 }
45
46 const int DefaultPlatform::kMaxThreadPoolSize = 8;
47
DefaultPlatform()48 DefaultPlatform::DefaultPlatform()
49 : initialized_(false), thread_pool_size_(0) {}
50
~DefaultPlatform()51 DefaultPlatform::~DefaultPlatform() {
52 if (tracing_controller_) {
53 tracing_controller_->StopTracing();
54 tracing_controller_.reset();
55 }
56
57 base::LockGuard<base::Mutex> guard(&lock_);
58 queue_.Terminate();
59 if (initialized_) {
60 for (auto i = thread_pool_.begin(); i != thread_pool_.end(); ++i) {
61 delete *i;
62 }
63 }
64 for (auto i = main_thread_queue_.begin(); i != main_thread_queue_.end();
65 ++i) {
66 while (!i->second.empty()) {
67 delete i->second.front();
68 i->second.pop();
69 }
70 }
71 for (auto i = main_thread_delayed_queue_.begin();
72 i != main_thread_delayed_queue_.end(); ++i) {
73 while (!i->second.empty()) {
74 delete i->second.top().second;
75 i->second.pop();
76 }
77 }
78 for (auto& i : main_thread_idle_queue_) {
79 while (!i.second.empty()) {
80 delete i.second.front();
81 i.second.pop();
82 }
83 }
84 }
85
86
SetThreadPoolSize(int thread_pool_size)87 void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) {
88 base::LockGuard<base::Mutex> guard(&lock_);
89 DCHECK(thread_pool_size >= 0);
90 if (thread_pool_size < 1) {
91 thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
92 }
93 thread_pool_size_ =
94 std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
95 }
96
97
EnsureInitialized()98 void DefaultPlatform::EnsureInitialized() {
99 base::LockGuard<base::Mutex> guard(&lock_);
100 if (initialized_) return;
101 initialized_ = true;
102
103 for (int i = 0; i < thread_pool_size_; ++i)
104 thread_pool_.push_back(new WorkerThread(&queue_));
105 }
106
107
PopTaskInMainThreadQueue(v8::Isolate * isolate)108 Task* DefaultPlatform::PopTaskInMainThreadQueue(v8::Isolate* isolate) {
109 auto it = main_thread_queue_.find(isolate);
110 if (it == main_thread_queue_.end() || it->second.empty()) {
111 return NULL;
112 }
113 Task* task = it->second.front();
114 it->second.pop();
115 return task;
116 }
117
118
PopTaskInMainThreadDelayedQueue(v8::Isolate * isolate)119 Task* DefaultPlatform::PopTaskInMainThreadDelayedQueue(v8::Isolate* isolate) {
120 auto it = main_thread_delayed_queue_.find(isolate);
121 if (it == main_thread_delayed_queue_.end() || it->second.empty()) {
122 return NULL;
123 }
124 double now = MonotonicallyIncreasingTime();
125 std::pair<double, Task*> deadline_and_task = it->second.top();
126 if (deadline_and_task.first > now) {
127 return NULL;
128 }
129 it->second.pop();
130 return deadline_and_task.second;
131 }
132
PopTaskInMainThreadIdleQueue(v8::Isolate * isolate)133 IdleTask* DefaultPlatform::PopTaskInMainThreadIdleQueue(v8::Isolate* isolate) {
134 auto it = main_thread_idle_queue_.find(isolate);
135 if (it == main_thread_idle_queue_.end() || it->second.empty()) {
136 return nullptr;
137 }
138 IdleTask* task = it->second.front();
139 it->second.pop();
140 return task;
141 }
142
PumpMessageLoop(v8::Isolate * isolate)143 bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate) {
144 Task* task = NULL;
145 {
146 base::LockGuard<base::Mutex> guard(&lock_);
147
148 // Move delayed tasks that hit their deadline to the main queue.
149 task = PopTaskInMainThreadDelayedQueue(isolate);
150 while (task != NULL) {
151 main_thread_queue_[isolate].push(task);
152 task = PopTaskInMainThreadDelayedQueue(isolate);
153 }
154
155 task = PopTaskInMainThreadQueue(isolate);
156
157 if (task == NULL) {
158 return false;
159 }
160 }
161 task->Run();
162 delete task;
163 return true;
164 }
165
RunIdleTasks(v8::Isolate * isolate,double idle_time_in_seconds)166 void DefaultPlatform::RunIdleTasks(v8::Isolate* isolate,
167 double idle_time_in_seconds) {
168 double deadline_in_seconds =
169 MonotonicallyIncreasingTime() + idle_time_in_seconds;
170 while (deadline_in_seconds > MonotonicallyIncreasingTime()) {
171 {
172 IdleTask* task;
173 {
174 base::LockGuard<base::Mutex> guard(&lock_);
175 task = PopTaskInMainThreadIdleQueue(isolate);
176 }
177 if (task == nullptr) return;
178 task->Run(deadline_in_seconds);
179 delete task;
180 }
181 }
182 }
183
CallOnBackgroundThread(Task * task,ExpectedRuntime expected_runtime)184 void DefaultPlatform::CallOnBackgroundThread(Task* task,
185 ExpectedRuntime expected_runtime) {
186 EnsureInitialized();
187 queue_.Append(task);
188 }
189
190
CallOnForegroundThread(v8::Isolate * isolate,Task * task)191 void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
192 base::LockGuard<base::Mutex> guard(&lock_);
193 main_thread_queue_[isolate].push(task);
194 }
195
196
CallDelayedOnForegroundThread(Isolate * isolate,Task * task,double delay_in_seconds)197 void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate,
198 Task* task,
199 double delay_in_seconds) {
200 base::LockGuard<base::Mutex> guard(&lock_);
201 double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
202 main_thread_delayed_queue_[isolate].push(std::make_pair(deadline, task));
203 }
204
CallIdleOnForegroundThread(Isolate * isolate,IdleTask * task)205 void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate,
206 IdleTask* task) {
207 base::LockGuard<base::Mutex> guard(&lock_);
208 main_thread_idle_queue_[isolate].push(task);
209 }
210
IdleTasksEnabled(Isolate * isolate)211 bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) { return true; }
212
MonotonicallyIncreasingTime()213 double DefaultPlatform::MonotonicallyIncreasingTime() {
214 return base::TimeTicks::HighResolutionNow().ToInternalValue() /
215 static_cast<double>(base::Time::kMicrosecondsPerSecond);
216 }
217
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)218 uint64_t DefaultPlatform::AddTraceEvent(
219 char phase, const uint8_t* category_enabled_flag, const char* name,
220 const char* scope, uint64_t id, uint64_t bind_id, int num_args,
221 const char** arg_names, const uint8_t* arg_types,
222 const uint64_t* arg_values,
223 std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
224 unsigned int flags) {
225 if (tracing_controller_) {
226 return tracing_controller_->AddTraceEvent(
227 phase, category_enabled_flag, name, scope, id, bind_id, num_args,
228 arg_names, arg_types, arg_values, arg_convertables, flags);
229 }
230
231 return 0;
232 }
233
UpdateTraceEventDuration(const uint8_t * category_enabled_flag,const char * name,uint64_t handle)234 void DefaultPlatform::UpdateTraceEventDuration(
235 const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {
236 if (tracing_controller_) {
237 tracing_controller_->UpdateTraceEventDuration(category_enabled_flag, name,
238 handle);
239 }
240 }
241
GetCategoryGroupEnabled(const char * name)242 const uint8_t* DefaultPlatform::GetCategoryGroupEnabled(const char* name) {
243 if (tracing_controller_) {
244 return tracing_controller_->GetCategoryGroupEnabled(name);
245 }
246 static uint8_t no = 0;
247 return &no;
248 }
249
250
GetCategoryGroupName(const uint8_t * category_enabled_flag)251 const char* DefaultPlatform::GetCategoryGroupName(
252 const uint8_t* category_enabled_flag) {
253 static const char dummy[] = "dummy";
254 return dummy;
255 }
256
SetTracingController(tracing::TracingController * tracing_controller)257 void DefaultPlatform::SetTracingController(
258 tracing::TracingController* tracing_controller) {
259 tracing_controller_.reset(tracing_controller);
260 }
261
NumberOfAvailableBackgroundThreads()262 size_t DefaultPlatform::NumberOfAvailableBackgroundThreads() {
263 return static_cast<size_t>(thread_pool_size_);
264 }
265
AddTraceStateObserver(TraceStateObserver * observer)266 void DefaultPlatform::AddTraceStateObserver(TraceStateObserver* observer) {
267 if (!tracing_controller_) return;
268 tracing_controller_->AddTraceStateObserver(observer);
269 }
270
RemoveTraceStateObserver(TraceStateObserver * observer)271 void DefaultPlatform::RemoveTraceStateObserver(TraceStateObserver* observer) {
272 if (!tracing_controller_) return;
273 tracing_controller_->RemoveTraceStateObserver(observer);
274 }
275
276 } // namespace platform
277 } // namespace v8
278