• 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/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