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 "src/base/logging.h"
11 #include "src/base/platform/platform.h"
12 #include "src/base/platform/time.h"
13 #include "src/base/sys-info.h"
14 #include "src/libplatform/worker-thread.h"
15
16 namespace v8 {
17 namespace platform {
18
19
CreateDefaultPlatform(int thread_pool_size)20 v8::Platform* CreateDefaultPlatform(int thread_pool_size) {
21 DefaultPlatform* platform = new DefaultPlatform();
22 platform->SetThreadPoolSize(thread_pool_size);
23 platform->EnsureInitialized();
24 return platform;
25 }
26
27
PumpMessageLoop(v8::Platform * platform,v8::Isolate * isolate)28 bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate) {
29 return reinterpret_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate);
30 }
31
32
33 const int DefaultPlatform::kMaxThreadPoolSize = 4;
34
35
DefaultPlatform()36 DefaultPlatform::DefaultPlatform()
37 : initialized_(false), thread_pool_size_(0) {}
38
39
~DefaultPlatform()40 DefaultPlatform::~DefaultPlatform() {
41 base::LockGuard<base::Mutex> guard(&lock_);
42 queue_.Terminate();
43 if (initialized_) {
44 for (auto i = thread_pool_.begin(); i != thread_pool_.end(); ++i) {
45 delete *i;
46 }
47 }
48 for (auto i = main_thread_queue_.begin(); i != main_thread_queue_.end();
49 ++i) {
50 while (!i->second.empty()) {
51 delete i->second.front();
52 i->second.pop();
53 }
54 }
55 for (auto i = main_thread_delayed_queue_.begin();
56 i != main_thread_delayed_queue_.end(); ++i) {
57 while (!i->second.empty()) {
58 delete i->second.top().second;
59 i->second.pop();
60 }
61 }
62 }
63
64
SetThreadPoolSize(int thread_pool_size)65 void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) {
66 base::LockGuard<base::Mutex> guard(&lock_);
67 DCHECK(thread_pool_size >= 0);
68 if (thread_pool_size < 1) {
69 thread_pool_size = base::SysInfo::NumberOfProcessors();
70 }
71 thread_pool_size_ =
72 std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
73 }
74
75
EnsureInitialized()76 void DefaultPlatform::EnsureInitialized() {
77 base::LockGuard<base::Mutex> guard(&lock_);
78 if (initialized_) return;
79 initialized_ = true;
80
81 for (int i = 0; i < thread_pool_size_; ++i)
82 thread_pool_.push_back(new WorkerThread(&queue_));
83 }
84
85
PopTaskInMainThreadQueue(v8::Isolate * isolate)86 Task* DefaultPlatform::PopTaskInMainThreadQueue(v8::Isolate* isolate) {
87 auto it = main_thread_queue_.find(isolate);
88 if (it == main_thread_queue_.end() || it->second.empty()) {
89 return NULL;
90 }
91 Task* task = it->second.front();
92 it->second.pop();
93 return task;
94 }
95
96
PopTaskInMainThreadDelayedQueue(v8::Isolate * isolate)97 Task* DefaultPlatform::PopTaskInMainThreadDelayedQueue(v8::Isolate* isolate) {
98 auto it = main_thread_delayed_queue_.find(isolate);
99 if (it == main_thread_delayed_queue_.end() || it->second.empty()) {
100 return NULL;
101 }
102 double now = MonotonicallyIncreasingTime();
103 std::pair<double, Task*> deadline_and_task = it->second.top();
104 if (deadline_and_task.first > now) {
105 return NULL;
106 }
107 it->second.pop();
108 return deadline_and_task.second;
109 }
110
111
PumpMessageLoop(v8::Isolate * isolate)112 bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate) {
113 Task* task = NULL;
114 {
115 base::LockGuard<base::Mutex> guard(&lock_);
116
117 // Move delayed tasks that hit their deadline to the main queue.
118 task = PopTaskInMainThreadDelayedQueue(isolate);
119 while (task != NULL) {
120 main_thread_queue_[isolate].push(task);
121 task = PopTaskInMainThreadDelayedQueue(isolate);
122 }
123
124 task = PopTaskInMainThreadQueue(isolate);
125
126 if (task == NULL) {
127 return false;
128 }
129 }
130 task->Run();
131 delete task;
132 return true;
133 }
134
135
CallOnBackgroundThread(Task * task,ExpectedRuntime expected_runtime)136 void DefaultPlatform::CallOnBackgroundThread(Task *task,
137 ExpectedRuntime expected_runtime) {
138 EnsureInitialized();
139 queue_.Append(task);
140 }
141
142
CallOnForegroundThread(v8::Isolate * isolate,Task * task)143 void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
144 base::LockGuard<base::Mutex> guard(&lock_);
145 main_thread_queue_[isolate].push(task);
146 }
147
148
CallDelayedOnForegroundThread(Isolate * isolate,Task * task,double delay_in_seconds)149 void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate,
150 Task* task,
151 double delay_in_seconds) {
152 base::LockGuard<base::Mutex> guard(&lock_);
153 double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
154 main_thread_delayed_queue_[isolate].push(std::make_pair(deadline, task));
155 }
156
157
CallIdleOnForegroundThread(Isolate * isolate,IdleTask * task)158 void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate,
159 IdleTask* task) {
160 UNREACHABLE();
161 }
162
163
IdleTasksEnabled(Isolate * isolate)164 bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) { return false; }
165
166
MonotonicallyIncreasingTime()167 double DefaultPlatform::MonotonicallyIncreasingTime() {
168 return base::TimeTicks::HighResolutionNow().ToInternalValue() /
169 static_cast<double>(base::Time::kMicrosecondsPerSecond);
170 }
171
172
AddTraceEvent(char phase,const uint8_t * category_enabled_flag,const char * name,uint64_t id,uint64_t bind_id,int num_args,const char ** arg_names,const uint8_t * arg_types,const uint64_t * arg_values,unsigned int flags)173 uint64_t DefaultPlatform::AddTraceEvent(
174 char phase, const uint8_t* category_enabled_flag, const char* name,
175 uint64_t id, uint64_t bind_id, int num_args, const char** arg_names,
176 const uint8_t* arg_types, const uint64_t* arg_values, unsigned int flags) {
177 return 0;
178 }
179
180
UpdateTraceEventDuration(const uint8_t * category_enabled_flag,const char * name,uint64_t handle)181 void DefaultPlatform::UpdateTraceEventDuration(
182 const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {}
183
184
GetCategoryGroupEnabled(const char * name)185 const uint8_t* DefaultPlatform::GetCategoryGroupEnabled(const char* name) {
186 static uint8_t no = 0;
187 return &no;
188 }
189
190
GetCategoryGroupName(const uint8_t * category_enabled_flag)191 const char* DefaultPlatform::GetCategoryGroupName(
192 const uint8_t* category_enabled_flag) {
193 static const char dummy[] = "dummy";
194 return dummy;
195 }
196 } // namespace platform
197 } // namespace v8
198