Line data Source code
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/debug/stack_trace.h"
12 : #include "src/base/logging.h"
13 : #include "src/base/platform/platform.h"
14 : #include "src/base/platform/time.h"
15 : #include "src/base/sys-info.h"
16 : #include "src/libplatform/worker-thread.h"
17 :
18 : namespace v8 {
19 : namespace platform {
20 :
21 : namespace {
22 :
23 0 : void PrintStackTrace() {
24 0 : v8::base::debug::StackTrace trace;
25 0 : trace.Print();
26 : // Avoid dumping duplicate stack trace on abort signal.
27 0 : v8::base::debug::DisableSignalStackDump();
28 0 : }
29 :
30 : } // namespace
31 :
32 54006 : v8::Platform* CreateDefaultPlatform(
33 : int thread_pool_size, IdleTaskSupport idle_task_support,
34 : InProcessStackDumping in_process_stack_dumping,
35 : v8::TracingController* tracing_controller) {
36 54006 : if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
37 54006 : v8::base::debug::EnableInProcessStackDumping();
38 : }
39 : DefaultPlatform* platform =
40 54006 : new DefaultPlatform(idle_task_support, tracing_controller);
41 54006 : platform->SetThreadPoolSize(thread_pool_size);
42 54006 : platform->EnsureInitialized();
43 54006 : return platform;
44 : }
45 :
46 223299 : bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate,
47 : MessageLoopBehavior behavior) {
48 : return static_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate,
49 223299 : behavior);
50 : }
51 :
52 44529 : void EnsureEventLoopInitialized(v8::Platform* platform, v8::Isolate* isolate) {
53 : return static_cast<DefaultPlatform*>(platform)->EnsureEventLoopInitialized(
54 44529 : isolate);
55 : }
56 :
57 148243 : void RunIdleTasks(v8::Platform* platform, v8::Isolate* isolate,
58 : double idle_time_in_seconds) {
59 : static_cast<DefaultPlatform*>(platform)->RunIdleTasks(isolate,
60 148243 : idle_time_in_seconds);
61 148243 : }
62 :
63 0 : void SetTracingController(
64 : v8::Platform* platform,
65 : v8::platform::tracing::TracingController* tracing_controller) {
66 : static_cast<DefaultPlatform*>(platform)->SetTracingController(
67 : tracing_controller);
68 0 : }
69 :
70 : const int DefaultPlatform::kMaxThreadPoolSize = 8;
71 :
72 54012 : DefaultPlatform::DefaultPlatform(IdleTaskSupport idle_task_support,
73 : v8::TracingController* tracing_controller)
74 : : initialized_(false),
75 : thread_pool_size_(0),
76 162036 : idle_task_support_(idle_task_support) {
77 54012 : if (tracing_controller) {
78 : tracing_controller_.reset(tracing_controller);
79 : } else {
80 54012 : tracing::TracingController* controller = new tracing::TracingController();
81 54012 : controller->Initialize(nullptr);
82 : tracing_controller_.reset(controller);
83 : }
84 54012 : }
85 :
86 212622 : DefaultPlatform::~DefaultPlatform() {
87 53157 : base::LockGuard<base::Mutex> guard(&lock_);
88 53157 : queue_.Terminate();
89 53157 : if (initialized_) {
90 478359 : for (auto i = thread_pool_.begin(); i != thread_pool_.end(); ++i) {
91 372057 : delete *i;
92 : }
93 : }
94 115288 : for (auto i = main_thread_queue_.begin(); i != main_thread_queue_.end();
95 : ++i) {
96 9186 : while (!i->second.empty()) {
97 212 : delete i->second.front();
98 : i->second.pop();
99 : }
100 : }
101 106712 : for (auto i = main_thread_delayed_queue_.begin();
102 : i != main_thread_delayed_queue_.end(); ++i) {
103 794 : while (!i->second.empty()) {
104 396 : delete i->second.top().second;
105 396 : i->second.pop();
106 : }
107 : }
108 108910 : for (auto& i : main_thread_idle_queue_) {
109 2599 : while (!i.second.empty()) {
110 3 : delete i.second.front();
111 : i.second.pop();
112 : }
113 : }
114 106308 : }
115 :
116 :
117 54006 : void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) {
118 54006 : base::LockGuard<base::Mutex> guard(&lock_);
119 : DCHECK_GE(thread_pool_size, 0);
120 54006 : if (thread_pool_size < 1) {
121 54006 : thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
122 : }
123 : thread_pool_size_ =
124 108012 : std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
125 54006 : }
126 :
127 :
128 861517 : void DefaultPlatform::EnsureInitialized() {
129 861517 : base::LockGuard<base::Mutex> guard(&lock_);
130 1723036 : if (initialized_) return;
131 54006 : initialized_ = true;
132 :
133 432048 : for (int i = 0; i < thread_pool_size_; ++i)
134 756084 : thread_pool_.push_back(new WorkerThread(&queue_));
135 : }
136 :
137 :
138 223311 : Task* DefaultPlatform::PopTaskInMainThreadQueue(v8::Isolate* isolate) {
139 : auto it = main_thread_queue_.find(isolate);
140 294753 : if (it == main_thread_queue_.end() || it->second.empty()) {
141 : return nullptr;
142 : }
143 50275 : Task* task = it->second.front();
144 : it->second.pop();
145 50275 : return task;
146 : }
147 :
148 :
149 223323 : Task* DefaultPlatform::PopTaskInMainThreadDelayedQueue(v8::Isolate* isolate) {
150 : auto it = main_thread_delayed_queue_.find(isolate);
151 227845 : if (it == main_thread_delayed_queue_.end() || it->second.empty()) {
152 : return nullptr;
153 : }
154 4503 : double now = MonotonicallyIncreasingTime();
155 4503 : std::pair<double, Task*> deadline_and_task = it->second.top();
156 4503 : if (deadline_and_task.first > now) {
157 : return nullptr;
158 : }
159 12 : it->second.pop();
160 12 : return deadline_and_task.second;
161 : }
162 :
163 153811 : IdleTask* DefaultPlatform::PopTaskInMainThreadIdleQueue(v8::Isolate* isolate) {
164 : auto it = main_thread_idle_queue_.find(isolate);
165 175997 : if (it == main_thread_idle_queue_.end() || it->second.empty()) {
166 : return nullptr;
167 : }
168 5590 : IdleTask* task = it->second.front();
169 : it->second.pop();
170 5590 : return task;
171 : }
172 :
173 44529 : void DefaultPlatform::EnsureEventLoopInitialized(v8::Isolate* isolate) {
174 44529 : base::LockGuard<base::Mutex> guard(&lock_);
175 44529 : if (event_loop_control_.count(isolate) == 0) {
176 : event_loop_control_.insert(std::make_pair(
177 53650 : isolate, std::unique_ptr<base::Semaphore>(new base::Semaphore(0))));
178 : }
179 44529 : }
180 :
181 193 : void DefaultPlatform::WaitForForegroundWork(v8::Isolate* isolate) {
182 : base::Semaphore* semaphore = nullptr;
183 : {
184 193 : base::LockGuard<base::Mutex> guard(&lock_);
185 : DCHECK_EQ(event_loop_control_.count(isolate), 1);
186 193 : semaphore = event_loop_control_[isolate].get();
187 : }
188 : DCHECK_NOT_NULL(semaphore);
189 193 : semaphore->Wait();
190 193 : }
191 :
192 223311 : bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate,
193 : MessageLoopBehavior behavior) {
194 223311 : if (behavior == MessageLoopBehavior::kWaitForWork) {
195 193 : WaitForForegroundWork(isolate);
196 : }
197 : Task* task = nullptr;
198 : {
199 223311 : base::LockGuard<base::Mutex> guard(&lock_);
200 :
201 : // Move delayed tasks that hit their deadline to the main queue.
202 223311 : task = PopTaskInMainThreadDelayedQueue(isolate);
203 446634 : while (task != nullptr) {
204 12 : ScheduleOnForegroundThread(isolate, task);
205 12 : task = PopTaskInMainThreadDelayedQueue(isolate);
206 : }
207 :
208 223311 : task = PopTaskInMainThreadQueue(isolate);
209 :
210 223311 : if (task == nullptr) {
211 : return behavior == MessageLoopBehavior::kWaitForWork;
212 : }
213 : }
214 50275 : task->Run();
215 50275 : delete task;
216 : return true;
217 : }
218 :
219 148244 : void DefaultPlatform::RunIdleTasks(v8::Isolate* isolate,
220 : double idle_time_in_seconds) {
221 : DCHECK_EQ(IdleTaskSupport::kEnabled, idle_task_support_);
222 : double deadline_in_seconds =
223 148244 : MonotonicallyIncreasingTime() + idle_time_in_seconds;
224 302078 : while (deadline_in_seconds > MonotonicallyIncreasingTime()) {
225 : {
226 : IdleTask* task;
227 : {
228 153811 : base::LockGuard<base::Mutex> guard(&lock_);
229 153811 : task = PopTaskInMainThreadIdleQueue(isolate);
230 : }
231 302055 : if (task == nullptr) return;
232 5590 : task->Run(deadline_in_seconds);
233 5590 : delete task;
234 : }
235 : }
236 : }
237 :
238 807511 : void DefaultPlatform::CallOnBackgroundThread(Task* task,
239 : ExpectedRuntime expected_runtime) {
240 807511 : EnsureInitialized();
241 807512 : queue_.Append(task);
242 807512 : }
243 :
244 50814 : void DefaultPlatform::ScheduleOnForegroundThread(v8::Isolate* isolate,
245 : Task* task) {
246 50814 : main_thread_queue_[isolate].push(task);
247 50814 : if (event_loop_control_.count(isolate) != 0) {
248 70216 : event_loop_control_[isolate]->Signal();
249 : }
250 50814 : }
251 :
252 50802 : void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
253 50802 : base::LockGuard<base::Mutex> guard(&lock_);
254 50802 : ScheduleOnForegroundThread(isolate, task);
255 50802 : }
256 :
257 :
258 409 : void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate,
259 : Task* task,
260 : double delay_in_seconds) {
261 409 : base::LockGuard<base::Mutex> guard(&lock_);
262 409 : double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
263 409 : main_thread_delayed_queue_[isolate].push(std::make_pair(deadline, task));
264 409 : }
265 :
266 5593 : void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate,
267 : IdleTask* task) {
268 5593 : base::LockGuard<base::Mutex> guard(&lock_);
269 5593 : main_thread_idle_queue_[isolate].push(task);
270 5593 : }
271 :
272 158101 : bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) {
273 158101 : return idle_task_support_ == IdleTaskSupport::kEnabled;
274 : }
275 :
276 7748983 : double DefaultPlatform::MonotonicallyIncreasingTime() {
277 23248269 : return base::TimeTicks::HighResolutionNow().ToInternalValue() /
278 15499286 : static_cast<double>(base::Time::kMicrosecondsPerSecond);
279 : }
280 :
281 184368 : double DefaultPlatform::CurrentClockTimeMillis() {
282 184368 : return base::OS::TimeCurrentMillis();
283 : }
284 :
285 1594309 : TracingController* DefaultPlatform::GetTracingController() {
286 1594309 : return tracing_controller_.get();
287 : }
288 :
289 29 : void DefaultPlatform::SetTracingController(
290 : v8::TracingController* tracing_controller) {
291 : DCHECK_NOT_NULL(tracing_controller);
292 : tracing_controller_.reset(tracing_controller);
293 29 : }
294 :
295 418911 : size_t DefaultPlatform::NumberOfAvailableBackgroundThreads() {
296 418911 : return static_cast<size_t>(thread_pool_size_);
297 : }
298 :
299 53977 : Platform::StackTracePrinter DefaultPlatform::GetStackTracePrinter() {
300 53977 : return PrintStackTrace;
301 : }
302 :
303 : } // namespace platform
304 : } // namespace v8
|