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