default-platform.cc 8.64 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 13
#include "src/base/logging.h"
#include "src/base/platform/platform.h"
14
#include "src/base/platform/time.h"
15
#include "src/base/sys-info.h"
16 17
#include "src/libplatform/default-background-task-runner.h"
#include "src/libplatform/default-foreground-task-runner.h"
18

19
namespace v8 {
20
namespace platform {
21

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

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

}  // namespace

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

v8::Platform* CreateDefaultPlatform(
    int thread_pool_size, IdleTaskSupport idle_task_support,
    InProcessStackDumping in_process_stack_dumping,
    v8::TracingController* tracing_controller) {
  return NewDefaultPlatform(
             thread_pool_size, idle_task_support, in_process_stack_dumping,
             std::unique_ptr<v8::TracingController>(tracing_controller))
      .release();
55 56
}

57 58
bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate,
                     MessageLoopBehavior behavior) {
59 60
  return static_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate,
                                                                  behavior);
61
}
62

63
void EnsureEventLoopInitialized(v8::Platform* platform, v8::Isolate* isolate) {
64 65
}

66 67
void RunIdleTasks(v8::Platform* platform, v8::Isolate* isolate,
                  double idle_time_in_seconds) {
68 69
  static_cast<DefaultPlatform*>(platform)->RunIdleTasks(isolate,
                                                        idle_time_in_seconds);
70 71
}

72 73 74
void SetTracingController(
    v8::Platform* platform,
    v8::platform::tracing::TracingController* tracing_controller) {
75
  static_cast<DefaultPlatform*>(platform)->SetTracingController(
76
      std::unique_ptr<v8::TracingController>(tracing_controller));
77 78
}

79
const int DefaultPlatform::kMaxThreadPoolSize = 8;
80

81 82 83
DefaultPlatform::DefaultPlatform(
    IdleTaskSupport idle_task_support,
    std::unique_ptr<v8::TracingController> tracing_controller)
84
    : thread_pool_size_(0),
85
      idle_task_support_(idle_task_support),
86 87
      tracing_controller_(std::move(tracing_controller)),
      time_function_for_testing_(nullptr) {
88
  if (!tracing_controller_) {
89 90 91 92 93
    tracing::TracingController* controller = new tracing::TracingController();
    controller->Initialize(nullptr);
    tracing_controller_.reset(controller);
  }
}
94 95

DefaultPlatform::~DefaultPlatform() {
96
  base::LockGuard<base::Mutex> guard(&lock_);
97 98 99
  if (background_task_runner_) background_task_runner_->Terminate();
  for (auto it : foreground_task_runner_map_) {
    it.second->Terminate();
100
  }
101 102 103
}

void DefaultPlatform::SetThreadPoolSize(int thread_pool_size) {
104
  base::LockGuard<base::Mutex> guard(&lock_);
105
  DCHECK_GE(thread_pool_size, 0);
106
  if (thread_pool_size < 1) {
107
    thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
108
  }
109 110
  thread_pool_size_ =
      std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
111
}
112

113
void DefaultPlatform::EnsureBackgroundTaskRunnerInitialized() {
114
  base::LockGuard<base::Mutex> guard(&lock_);
115 116 117
  if (!background_task_runner_) {
    background_task_runner_ =
        std::make_shared<DefaultBackgroundTaskRunner>(thread_pool_size_);
118 119 120
  }
}

121
namespace {
122

123 124 125
double DefaultTimeFunction() {
  return base::TimeTicks::HighResolutionNow().ToInternalValue() /
         static_cast<double>(base::Time::kMicrosecondsPerSecond);
126 127
}

128
}  // namespace
129

130 131
void DefaultPlatform::SetTimeFunctionForTesting(
    DefaultPlatform::TimeFunction time_function) {
132
  base::LockGuard<base::Mutex> guard(&lock_);
133 134 135
  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());
136 137 138 139
}

bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate,
                                      MessageLoopBehavior behavior) {
140 141
  bool failed_result = behavior == MessageLoopBehavior::kWaitForWork;
  std::shared_ptr<DefaultForegroundTaskRunner> task_runner;
142 143
  {
    base::LockGuard<base::Mutex> guard(&lock_);
144 145 146
    if (foreground_task_runner_map_.find(isolate) ==
        foreground_task_runner_map_.end()) {
      return failed_result;
147
    }
148 149 150 151 152
    task_runner = foreground_task_runner_map_[isolate];
  }
  if (behavior == MessageLoopBehavior::kWaitForWork) {
    task_runner->WaitForTask();
  }
153

154 155
  std::unique_ptr<Task> task = task_runner->PopTaskFromQueue();
  if (!task) return failed_result;
156

157 158 159 160
  task->Run();
  return true;
}

161 162
void DefaultPlatform::RunIdleTasks(v8::Isolate* isolate,
                                   double idle_time_in_seconds) {
163
  DCHECK_EQ(IdleTaskSupport::kEnabled, idle_task_support_);
164 165 166 167 168 169 170 171 172
  std::shared_ptr<DefaultForegroundTaskRunner> task_runner;
  {
    base::LockGuard<base::Mutex> guard(&lock_);
    if (foreground_task_runner_map_.find(isolate) ==
        foreground_task_runner_map_.end()) {
      return;
    }
    task_runner = foreground_task_runner_map_[isolate];
  }
173 174
  double deadline_in_seconds =
      MonotonicallyIncreasingTime() + idle_time_in_seconds;
175

176
  while (deadline_in_seconds > MonotonicallyIncreasingTime()) {
177 178 179
    std::unique_ptr<IdleTask> task = task_runner->PopTaskFromIdleQueue();
    if (!task) return;
    task->Run(deadline_in_seconds);
180 181
  }
}
182

183 184 185 186 187 188 189 190 191 192 193 194
std::shared_ptr<TaskRunner> DefaultPlatform::GetForegroundTaskRunner(
    v8::Isolate* isolate) {
  base::LockGuard<base::Mutex> guard(&lock_);
  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];
195 196
}

197 198 199 200 201 202 203 204 205
std::shared_ptr<TaskRunner> DefaultPlatform::GetBackgroundTaskRunner(
    v8::Isolate*) {
  EnsureBackgroundTaskRunnerInitialized();
  return background_task_runner_;
}

void DefaultPlatform::CallOnBackgroundThread(Task* task,
                                             ExpectedRuntime expected_runtime) {
  GetBackgroundTaskRunner(nullptr)->PostTask(std::unique_ptr<Task>(task));
206
}
207 208

void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
209
  GetForegroundTaskRunner(isolate)->PostTask(std::unique_ptr<Task>(task));
210 211
}

212

213 214 215
void DefaultPlatform::CallDelayedOnForegroundThread(Isolate* isolate,
                                                    Task* task,
                                                    double delay_in_seconds) {
216 217
  GetForegroundTaskRunner(isolate)->PostDelayedTask(std::unique_ptr<Task>(task),
                                                    delay_in_seconds);
218 219
}

220 221
void DefaultPlatform::CallIdleOnForegroundThread(Isolate* isolate,
                                                 IdleTask* task) {
222 223
  GetForegroundTaskRunner(isolate)->PostIdleTask(
      std::unique_ptr<IdleTask>(task));
224 225
}

226 227 228
bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) {
  return idle_task_support_ == IdleTaskSupport::kEnabled;
}
229

230
double DefaultPlatform::MonotonicallyIncreasingTime() {
231 232
  if (time_function_for_testing_) return time_function_for_testing_();
  return DefaultTimeFunction();
233
}
234

235 236 237 238
double DefaultPlatform::CurrentClockTimeMillis() {
  return base::OS::TimeCurrentMillis();
}

239 240 241 242
TracingController* DefaultPlatform::GetTracingController() {
  return tracing_controller_.get();
}

243
void DefaultPlatform::SetTracingController(
244 245 246
    std::unique_ptr<v8::TracingController> tracing_controller) {
  DCHECK_NOT_NULL(tracing_controller.get());
  tracing_controller_ = std::move(tracing_controller);
247
}
248

249 250 251 252
size_t DefaultPlatform::NumberOfAvailableBackgroundThreads() {
  return static_cast<size_t>(thread_pool_size_);
}

253 254 255 256
Platform::StackTracePrinter DefaultPlatform::GetStackTracePrinter() {
  return PrintStackTrace;
}

257 258
}  // namespace platform
}  // namespace v8