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