default-foreground-task-runner.cc 6.53 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/libplatform/default-foreground-task-runner.h"

#include "src/base/platform/mutex.h"
#include "src/libplatform/default-platform.h"

namespace v8 {
namespace platform {

13 14 15 16 17 18 19 20 21 22 23 24
DefaultForegroundTaskRunner::RunTaskScope::RunTaskScope(
    std::shared_ptr<DefaultForegroundTaskRunner> task_runner)
    : task_runner_(task_runner) {
  DCHECK_GE(task_runner->nesting_depth_, 0);
  task_runner->nesting_depth_++;
}

DefaultForegroundTaskRunner::RunTaskScope::~RunTaskScope() {
  DCHECK_GT(task_runner_->nesting_depth_, 0);
  task_runner_->nesting_depth_--;
}

25 26
DefaultForegroundTaskRunner::DefaultForegroundTaskRunner(
    IdleTaskSupport idle_task_support, TimeFunction time_function)
27
    : idle_task_support_(idle_task_support), time_function_(time_function) {}
28 29

void DefaultForegroundTaskRunner::Terminate() {
30
  base::MutexGuard guard(&lock_);
31 32 33
  terminated_ = true;

  // Drain the task queues.
34
  while (!task_queue_.empty()) task_queue_.pop_front();
35 36 37 38
  while (!delayed_task_queue_.empty()) delayed_task_queue_.pop();
  while (!idle_task_queue_.empty()) idle_task_queue_.pop();
}

39
void DefaultForegroundTaskRunner::PostTaskLocked(std::unique_ptr<Task> task,
40
                                                 Nestability nestability,
41
                                                 const base::MutexGuard&) {
42
  if (terminated_) return;
43
  task_queue_.push_back(std::make_pair(nestability, std::move(task)));
44
  event_loop_control_.NotifyOne();
45 46 47
}

void DefaultForegroundTaskRunner::PostTask(std::unique_ptr<Task> task) {
48
  base::MutexGuard guard(&lock_);
49
  PostTaskLocked(std::move(task), kNestable, guard);
50 51 52 53 54 55
}

double DefaultForegroundTaskRunner::MonotonicallyIncreasingTime() {
  return time_function_();
}

56 57 58
void DefaultForegroundTaskRunner::PostDelayedTaskLocked(
    std::unique_ptr<Task> task, double delay_in_seconds,
    Nestability nestability, const base::MutexGuard&) {
59 60 61
  DCHECK_GE(delay_in_seconds, 0.0);
  if (terminated_) return;
  double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
62 63 64 65 66 67 68 69 70 71 72 73 74 75
  delayed_task_queue_.push({deadline, nestability, std::move(task)});
  event_loop_control_.NotifyOne();
}

void DefaultForegroundTaskRunner::PostDelayedTask(std::unique_ptr<Task> task,
                                                  double delay_in_seconds) {
  base::MutexGuard guard(&lock_);
  PostDelayedTaskLocked(std::move(task), delay_in_seconds, kNestable, guard);
}

void DefaultForegroundTaskRunner::PostNonNestableDelayedTask(
    std::unique_ptr<Task> task, double delay_in_seconds) {
  base::MutexGuard guard(&lock_);
  PostDelayedTaskLocked(std::move(task), delay_in_seconds, kNonNestable, guard);
76 77 78 79
}

void DefaultForegroundTaskRunner::PostIdleTask(std::unique_ptr<IdleTask> task) {
  CHECK_EQ(IdleTaskSupport::kEnabled, idle_task_support_);
80
  base::MutexGuard guard(&lock_);
81 82 83 84 85 86 87 88
  if (terminated_) return;
  idle_task_queue_.push(std::move(task));
}

bool DefaultForegroundTaskRunner::IdleTasksEnabled() {
  return idle_task_support_ == IdleTaskSupport::kEnabled;
}

89 90
void DefaultForegroundTaskRunner::PostNonNestableTask(
    std::unique_ptr<Task> task) {
91 92
  base::MutexGuard guard(&lock_);
  PostTaskLocked(std::move(task), kNonNestable, guard);
93 94 95 96 97 98
}

bool DefaultForegroundTaskRunner::NonNestableTasksEnabled() const {
  return true;
}

99 100 101 102 103 104 105 106
bool DefaultForegroundTaskRunner::HasPoppableTaskInQueue() const {
  if (nesting_depth_ == 0) return !task_queue_.empty();
  for (auto it = task_queue_.cbegin(); it != task_queue_.cend(); it++) {
    if (it->first == kNestable) return true;
  }
  return false;
}

107 108 109 110 111 112 113 114 115 116 117
void DefaultForegroundTaskRunner::MoveExpiredDelayedTasks(
    const base::MutexGuard& guard) {
  Nestability nestability;
  std::unique_ptr<Task> task =
      PopTaskFromDelayedQueueLocked(guard, &nestability);
  while (task) {
    PostTaskLocked(std::move(task), nestability, guard);
    task = PopTaskFromDelayedQueueLocked(guard, &nestability);
  }
}

118 119
std::unique_ptr<Task> DefaultForegroundTaskRunner::PopTaskFromQueue(
    MessageLoopBehavior wait_for_work) {
120
  base::MutexGuard guard(&lock_);
121
  MoveExpiredDelayedTasks(guard);
122

123
  while (!HasPoppableTaskInQueue()) {
124 125
    if (wait_for_work == MessageLoopBehavior::kDoNotWait) return {};
    WaitForTaskLocked(guard);
126
    MoveExpiredDelayedTasks(guard);
127
  }
128

129 130 131 132 133 134 135
  auto it = task_queue_.begin();
  for (; it != task_queue_.end(); it++) {
    // When the task queue is nested (i.e. popping a task from the queue from
    // within a task), only nestable tasks may run. Otherwise, any task may run.
    if (nesting_depth_ == 0 || it->first == kNestable) break;
  }
  DCHECK(it != task_queue_.end());
136
  std::unique_ptr<Task> task = std::move(it->second);
137
  task_queue_.erase(it);
138 139 140 141 142 143

  return task;
}

std::unique_ptr<Task>
DefaultForegroundTaskRunner::PopTaskFromDelayedQueueLocked(
144
    const base::MutexGuard&, Nestability* nestability) {
145 146 147
  if (delayed_task_queue_.empty()) return {};

  double now = MonotonicallyIncreasingTime();
148 149
  const DelayedEntry& entry = delayed_task_queue_.top();
  if (entry.timeout_time > now) return {};
150 151 152 153 154 155
  // The const_cast here is necessary because there does not exist a clean way
  // to get a unique_ptr out of the priority queue. We provide the priority
  // queue with a custom comparison operator to make sure that the priority
  // queue does not access the unique_ptr. Therefore it should be safe to reset
  // the unique_ptr in the priority queue here. Note that the DelayedEntry is
  // removed from the priority_queue immediately afterwards.
156 157
  std::unique_ptr<Task> task = std::move(const_cast<DelayedEntry&>(entry).task);
  *nestability = entry.nestability;
158
  delayed_task_queue_.pop();
159
  return task;
160 161 162
}

std::unique_ptr<IdleTask> DefaultForegroundTaskRunner::PopTaskFromIdleQueue() {
163
  base::MutexGuard guard(&lock_);
164 165 166 167 168 169 170 171
  if (idle_task_queue_.empty()) return {};

  std::unique_ptr<IdleTask> task = std::move(idle_task_queue_.front());
  idle_task_queue_.pop();

  return task;
}

172
void DefaultForegroundTaskRunner::WaitForTaskLocked(const base::MutexGuard&) {
173 174 175 176 177 178 179 180 181 182 183 184 185 186
  if (!delayed_task_queue_.empty()) {
    double now = MonotonicallyIncreasingTime();
    const DelayedEntry& entry = delayed_task_queue_.top();
    double time_until_task = entry.timeout_time - now;
    if (time_until_task > 0) {
      bool woken_up = event_loop_control_.WaitFor(
          &lock_,
          base::TimeDelta::FromMicroseconds(
              time_until_task * base::TimeConstants::kMicrosecondsPerSecond));
      USE(woken_up);
    }
  } else {
    event_loop_control_.Wait(&lock_);
  }
187
}
188 189 190

}  // namespace platform
}  // namespace v8