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
16namespace v8 {
17namespace platform {
18
19
20v8::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
28bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate) {
29  return reinterpret_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate);
30}
31
32
33const int DefaultPlatform::kMaxThreadPoolSize = 4;
34
35
36DefaultPlatform::DefaultPlatform()
37    : initialized_(false), thread_pool_size_(0) {}
38
39
40DefaultPlatform::~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
65void 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
76void 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
86Task* 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
97Task* 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
112bool 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
136void DefaultPlatform::CallOnBackgroundThread(Task *task,
137                                             ExpectedRuntime expected_runtime) {
138  EnsureInitialized();
139  queue_.Append(task);
140}
141
142
143void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
144  base::LockGuard<base::Mutex> guard(&lock_);
145  main_thread_queue_[isolate].push(task);
146}
147
148
149void 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
158void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate,
159                                                 IdleTask* task) {
160  UNREACHABLE();
161}
162
163
164bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) { return false; }
165
166
167double DefaultPlatform::MonotonicallyIncreasingTime() {
168  return base::TimeTicks::HighResolutionNow().ToInternalValue() /
169         static_cast<double>(base::Time::kMicrosecondsPerSecond);
170}
171
172
173uint64_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
181void DefaultPlatform::UpdateTraceEventDuration(
182    const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {}
183
184
185const uint8_t* DefaultPlatform::GetCategoryGroupEnabled(const char* name) {
186  static uint8_t no = 0;
187  return &no;
188}
189
190
191const 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