default-platform.cc 8.42 KB
Newer Older
1
// Copyright 2013 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/libplatform/default-platform.h"
6

7
#include <algorithm>
8 9
#include <queue>

10
#include "include/libplatform/libplatform.h"
11
#include "src/base/debug/stack_trace.h"
12
#include "src/base/logging.h"
13
#include "src/base/page-allocator.h"
14
#include "src/base/platform/platform.h"
15
#include "src/base/platform/time.h"
16
#include "src/base/sys-info.h"
17
#include "src/libplatform/default-foreground-task-runner.h"
18
#include "src/libplatform/default-worker-threads-task-runner.h"
19

20
namespace v8 {
21
namespace platform {
22

23 24 25 26 27 28 29 30 31 32 33
namespace {

void PrintStackTrace() {
  v8::base::debug::StackTrace trace;
  trace.Print();
  // Avoid dumping duplicate stack trace on abort signal.
  v8::base::debug::DisableSignalStackDump();
}

}  // namespace

34
std::unique_ptr<v8::Platform> NewDefaultPlatform(
35
    int thread_pool_size, IdleTaskSupport idle_task_support,
36
    InProcessStackDumping in_process_stack_dumping,
37
    std::unique_ptr<v8::TracingController> tracing_controller) {
38 39 40
  if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
    v8::base::debug::EnableInProcessStackDumping();
  }
41 42
  std::unique_ptr<DefaultPlatform> platform(
      new DefaultPlatform(idle_task_support, std::move(tracing_controller)));
43
  platform->SetThreadPoolSize(thread_pool_size);
44
  platform->EnsureBackgroundTaskRunnerInitialized();
45 46 47
  return std::move(platform);
}

48 49
bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate,
                     MessageLoopBehavior behavior) {
50 51
  return static_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate,
                                                                  behavior);
52
}
53

54 55
void RunIdleTasks(v8::Platform* platform, v8::Isolate* isolate,
                  double idle_time_in_seconds) {
56 57
  static_cast<DefaultPlatform*>(platform)->RunIdleTasks(isolate,
                                                        idle_time_in_seconds);
58 59
}

60 61 62
void SetTracingController(
    v8::Platform* platform,
    v8::platform::tracing::TracingController* tracing_controller) {
63
  static_cast<DefaultPlatform*>(platform)->SetTracingController(
64
      std::unique_ptr<v8::TracingController>(tracing_controller));
65 66
}

67
const int DefaultPlatform::kMaxThreadPoolSize = 8;
68

69 70 71
DefaultPlatform::DefaultPlatform(
    IdleTaskSupport idle_task_support,
    std::unique_ptr<v8::TracingController> tracing_controller)
72
    : thread_pool_size_(0),
73
      idle_task_support_(idle_task_support),
74
      tracing_controller_(std::move(tracing_controller)),
75
      page_allocator_(new v8::base::PageAllocator()),
76
      time_function_for_testing_(nullptr) {
77
  if (!tracing_controller_) {
78 79 80 81 82
    tracing::TracingController* controller = new tracing::TracingController();
    controller->Initialize(nullptr);
    tracing_controller_.reset(controller);
  }
}
83 84

DefaultPlatform::~DefaultPlatform() {
85
  base::MutexGuard guard(&lock_);
86
  if (worker_threads_task_runner_) worker_threads_task_runner_->Terminate();
87 88
  for (auto it : foreground_task_runner_map_) {
    it.second->Terminate();
89
  }
90 91 92
}

void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) {
93
  base::MutexGuard guard(&lock_);
94
  DCHECK_GE(thread_pool_size, 0);
95
  if (thread_pool_size < 1) {
96
    thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
97
  }
98 99
  thread_pool_size_ =
      std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
100
}
101

102
namespace {
103

104 105 106
double DefaultTimeFunction() {
  return base::TimeTicks::HighResolutionNow().ToInternalValue() /
         static_cast<double>(base::Time::kMicrosecondsPerSecond);
107 108
}

109
}  // namespace
110

111 112 113 114 115 116 117 118 119 120 121
void DefaultPlatform::EnsureBackgroundTaskRunnerInitialized() {
  base::MutexGuard guard(&lock_);
  if (!worker_threads_task_runner_) {
    worker_threads_task_runner_ =
        std::make_shared<DefaultWorkerThreadsTaskRunner>(
            thread_pool_size_, time_function_for_testing_
                                   ? time_function_for_testing_
                                   : DefaultTimeFunction);
  }
}

122 123
void DefaultPlatform::SetTimeFunctionForTesting(
    DefaultPlatform::TimeFunction time_function) {
124
  base::MutexGuard guard(&lock_);
125 126 127
  time_function_for_testing_ = time_function;
  // The time function has to be right after the construction of the platform.
  DCHECK(foreground_task_runner_map_.empty());
128 129 130
}

bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate,
131 132
                                      MessageLoopBehavior wait_for_work) {
  bool failed_result = wait_for_work == MessageLoopBehavior::kWaitForWork;
133
  std::shared_ptr<DefaultForegroundTaskRunner> task_runner;
134
  {
135
    base::MutexGuard guard(&lock_);
136 137 138
    auto it = foreground_task_runner_map_.find(isolate);
    if (it == foreground_task_runner_map_.end()) return failed_result;
    task_runner = it->second;
139
  }
140

141
  std::unique_ptr<Task> task = task_runner->PopTaskFromQueue(wait_for_work);
142
  if (!task) return failed_result;
143

144 145 146 147
  task->Run();
  return true;
}

148 149
void DefaultPlatform::RunIdleTasks(v8::Isolate* isolate,
                                   double idle_time_in_seconds) {
150
  DCHECK_EQ(IdleTaskSupport::kEnabled, idle_task_support_);
151 152
  std::shared_ptr<DefaultForegroundTaskRunner> task_runner;
  {
153
    base::MutexGuard guard(&lock_);
154 155 156 157 158 159
    if (foreground_task_runner_map_.find(isolate) ==
        foreground_task_runner_map_.end()) {
      return;
    }
    task_runner = foreground_task_runner_map_[isolate];
  }
160 161
  double deadline_in_seconds =
      MonotonicallyIncreasingTime() + idle_time_in_seconds;
162

163
  while (deadline_in_seconds > MonotonicallyIncreasingTime()) {
164 165 166
    std::unique_ptr<IdleTask> task = task_runner->PopTaskFromIdleQueue();
    if (!task) return;
    task->Run(deadline_in_seconds);
167 168
  }
}
169

170 171
std::shared_ptr<TaskRunner> DefaultPlatform::GetForegroundTaskRunner(
    v8::Isolate* isolate) {
172
  base::MutexGuard guard(&lock_);
173 174 175 176 177 178 179 180 181
  if (foreground_task_runner_map_.find(isolate) ==
      foreground_task_runner_map_.end()) {
    foreground_task_runner_map_.insert(std::make_pair(
        isolate, std::make_shared<DefaultForegroundTaskRunner>(
                     idle_task_support_, time_function_for_testing_
                                             ? time_function_for_testing_
                                             : DefaultTimeFunction)));
  }
  return foreground_task_runner_map_[isolate];
182 183
}

184
void DefaultPlatform::CallOnWorkerThread(std::unique_ptr<Task> task) {
185 186
  EnsureBackgroundTaskRunnerInitialized();
  worker_threads_task_runner_->PostTask(std::move(task));
187
}
188

189 190
void DefaultPlatform::CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
                                                double delay_in_seconds) {
191 192 193
  EnsureBackgroundTaskRunnerInitialized();
  worker_threads_task_runner_->PostDelayedTask(std::move(task),
                                               delay_in_seconds);
194 195
}

196
void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
197
  GetForegroundTaskRunner(isolate)->PostTask(std::unique_ptr<Task>(task));
198 199
}

200 201 202
void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate,
                                                    Task* task,
                                                    double delay_in_seconds) {
203 204
  GetForegroundTaskRunner(isolate)->PostDelayedTask(std::unique_ptr<Task>(task),
                                                    delay_in_seconds);
205 206
}

207 208
void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate,
                                                 IdleTask* task) {
209 210
  GetForegroundTaskRunner(isolate)->PostIdleTask(
      std::unique_ptr<IdleTask>(task));
211 212
}

213 214 215
bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) {
  return idle_task_support_ == IdleTaskSupport::kEnabled;
}
216

217
double DefaultPlatform::MonotonicallyIncreasingTime() {
218 219
  if (time_function_for_testing_) return time_function_for_testing_();
  return DefaultTimeFunction();
220
}
221

222 223 224 225
double DefaultPlatform::CurrentClockTimeMillis() {
  return base::OS::TimeCurrentMillis();
}

226 227 228 229
TracingController* DefaultPlatform::GetTracingController() {
  return tracing_controller_.get();
}

230
void DefaultPlatform::SetTracingController(
231 232 233
    std::unique_ptr<v8::TracingController> tracing_controller) {
  DCHECK_NOT_NULL(tracing_controller.get());
  tracing_controller_ = std::move(tracing_controller);
234
}
235

236
int DefaultPlatform::NumberOfWorkerThreads() { return thread_pool_size_; }
237

238 239 240 241
Platform::StackTracePrinter DefaultPlatform::GetStackTracePrinter() {
  return PrintStackTrace;
}

242 243 244 245
v8::PageAllocator* DefaultPlatform::GetPageAllocator() {
  return page_allocator_.get();
}

246 247
}  // namespace platform
}  // namespace v8