11cb0ef41Sopenharmony_ci// Copyright 2017 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/libplatform/default-foreground-task-runner.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/base/platform/mutex.h"
81cb0ef41Sopenharmony_ci#include "src/libplatform/default-platform.h"
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_cinamespace v8 {
111cb0ef41Sopenharmony_cinamespace platform {
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ciDefaultForegroundTaskRunner::RunTaskScope::RunTaskScope(
141cb0ef41Sopenharmony_ci    std::shared_ptr<DefaultForegroundTaskRunner> task_runner)
151cb0ef41Sopenharmony_ci    : task_runner_(task_runner) {
161cb0ef41Sopenharmony_ci  DCHECK_GE(task_runner->nesting_depth_, 0);
171cb0ef41Sopenharmony_ci  task_runner->nesting_depth_++;
181cb0ef41Sopenharmony_ci}
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ciDefaultForegroundTaskRunner::RunTaskScope::~RunTaskScope() {
211cb0ef41Sopenharmony_ci  DCHECK_GT(task_runner_->nesting_depth_, 0);
221cb0ef41Sopenharmony_ci  task_runner_->nesting_depth_--;
231cb0ef41Sopenharmony_ci}
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciDefaultForegroundTaskRunner::DefaultForegroundTaskRunner(
261cb0ef41Sopenharmony_ci    IdleTaskSupport idle_task_support, TimeFunction time_function)
271cb0ef41Sopenharmony_ci    : idle_task_support_(idle_task_support), time_function_(time_function) {}
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_civoid DefaultForegroundTaskRunner::Terminate() {
301cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
311cb0ef41Sopenharmony_ci  terminated_ = true;
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci  // Drain the task queues.
341cb0ef41Sopenharmony_ci  while (!task_queue_.empty()) task_queue_.pop_front();
351cb0ef41Sopenharmony_ci  while (!delayed_task_queue_.empty()) delayed_task_queue_.pop();
361cb0ef41Sopenharmony_ci  while (!idle_task_queue_.empty()) idle_task_queue_.pop();
371cb0ef41Sopenharmony_ci}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_civoid DefaultForegroundTaskRunner::PostTaskLocked(std::unique_ptr<Task> task,
401cb0ef41Sopenharmony_ci                                                 Nestability nestability,
411cb0ef41Sopenharmony_ci                                                 const base::MutexGuard&) {
421cb0ef41Sopenharmony_ci  if (terminated_) return;
431cb0ef41Sopenharmony_ci  task_queue_.push_back(std::make_pair(nestability, std::move(task)));
441cb0ef41Sopenharmony_ci  event_loop_control_.NotifyOne();
451cb0ef41Sopenharmony_ci}
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_civoid DefaultForegroundTaskRunner::PostTask(std::unique_ptr<Task> task) {
481cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
491cb0ef41Sopenharmony_ci  PostTaskLocked(std::move(task), kNestable, guard);
501cb0ef41Sopenharmony_ci}
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_cidouble DefaultForegroundTaskRunner::MonotonicallyIncreasingTime() {
531cb0ef41Sopenharmony_ci  return time_function_();
541cb0ef41Sopenharmony_ci}
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_civoid DefaultForegroundTaskRunner::PostDelayedTaskLocked(
571cb0ef41Sopenharmony_ci    std::unique_ptr<Task> task, double delay_in_seconds,
581cb0ef41Sopenharmony_ci    Nestability nestability, const base::MutexGuard&) {
591cb0ef41Sopenharmony_ci  DCHECK_GE(delay_in_seconds, 0.0);
601cb0ef41Sopenharmony_ci  if (terminated_) return;
611cb0ef41Sopenharmony_ci  double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
621cb0ef41Sopenharmony_ci  delayed_task_queue_.push({deadline, nestability, std::move(task)});
631cb0ef41Sopenharmony_ci  event_loop_control_.NotifyOne();
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_civoid DefaultForegroundTaskRunner::PostDelayedTask(std::unique_ptr<Task> task,
671cb0ef41Sopenharmony_ci                                                  double delay_in_seconds) {
681cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
691cb0ef41Sopenharmony_ci  PostDelayedTaskLocked(std::move(task), delay_in_seconds, kNestable, guard);
701cb0ef41Sopenharmony_ci}
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_civoid DefaultForegroundTaskRunner::PostNonNestableDelayedTask(
731cb0ef41Sopenharmony_ci    std::unique_ptr<Task> task, double delay_in_seconds) {
741cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
751cb0ef41Sopenharmony_ci  PostDelayedTaskLocked(std::move(task), delay_in_seconds, kNonNestable, guard);
761cb0ef41Sopenharmony_ci}
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_civoid DefaultForegroundTaskRunner::PostIdleTask(std::unique_ptr<IdleTask> task) {
791cb0ef41Sopenharmony_ci  CHECK_EQ(IdleTaskSupport::kEnabled, idle_task_support_);
801cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
811cb0ef41Sopenharmony_ci  if (terminated_) return;
821cb0ef41Sopenharmony_ci  idle_task_queue_.push(std::move(task));
831cb0ef41Sopenharmony_ci}
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_cibool DefaultForegroundTaskRunner::IdleTasksEnabled() {
861cb0ef41Sopenharmony_ci  return idle_task_support_ == IdleTaskSupport::kEnabled;
871cb0ef41Sopenharmony_ci}
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_civoid DefaultForegroundTaskRunner::PostNonNestableTask(
901cb0ef41Sopenharmony_ci    std::unique_ptr<Task> task) {
911cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
921cb0ef41Sopenharmony_ci  PostTaskLocked(std::move(task), kNonNestable, guard);
931cb0ef41Sopenharmony_ci}
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_cibool DefaultForegroundTaskRunner::NonNestableTasksEnabled() const {
961cb0ef41Sopenharmony_ci  return true;
971cb0ef41Sopenharmony_ci}
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_cibool DefaultForegroundTaskRunner::HasPoppableTaskInQueue() const {
1001cb0ef41Sopenharmony_ci  if (nesting_depth_ == 0) return !task_queue_.empty();
1011cb0ef41Sopenharmony_ci  for (auto it = task_queue_.cbegin(); it != task_queue_.cend(); it++) {
1021cb0ef41Sopenharmony_ci    if (it->first == kNestable) return true;
1031cb0ef41Sopenharmony_ci  }
1041cb0ef41Sopenharmony_ci  return false;
1051cb0ef41Sopenharmony_ci}
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_civoid DefaultForegroundTaskRunner::MoveExpiredDelayedTasks(
1081cb0ef41Sopenharmony_ci    const base::MutexGuard& guard) {
1091cb0ef41Sopenharmony_ci  Nestability nestability;
1101cb0ef41Sopenharmony_ci  std::unique_ptr<Task> task =
1111cb0ef41Sopenharmony_ci      PopTaskFromDelayedQueueLocked(guard, &nestability);
1121cb0ef41Sopenharmony_ci  while (task) {
1131cb0ef41Sopenharmony_ci    PostTaskLocked(std::move(task), nestability, guard);
1141cb0ef41Sopenharmony_ci    task = PopTaskFromDelayedQueueLocked(guard, &nestability);
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci}
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_cistd::unique_ptr<Task> DefaultForegroundTaskRunner::PopTaskFromQueue(
1191cb0ef41Sopenharmony_ci    MessageLoopBehavior wait_for_work) {
1201cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
1211cb0ef41Sopenharmony_ci  MoveExpiredDelayedTasks(guard);
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  while (!HasPoppableTaskInQueue()) {
1241cb0ef41Sopenharmony_ci    if (wait_for_work == MessageLoopBehavior::kDoNotWait) return {};
1251cb0ef41Sopenharmony_ci    WaitForTaskLocked(guard);
1261cb0ef41Sopenharmony_ci    MoveExpiredDelayedTasks(guard);
1271cb0ef41Sopenharmony_ci  }
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  auto it = task_queue_.begin();
1301cb0ef41Sopenharmony_ci  for (; it != task_queue_.end(); it++) {
1311cb0ef41Sopenharmony_ci    // When the task queue is nested (i.e. popping a task from the queue from
1321cb0ef41Sopenharmony_ci    // within a task), only nestable tasks may run. Otherwise, any task may run.
1331cb0ef41Sopenharmony_ci    if (nesting_depth_ == 0 || it->first == kNestable) break;
1341cb0ef41Sopenharmony_ci  }
1351cb0ef41Sopenharmony_ci  DCHECK(it != task_queue_.end());
1361cb0ef41Sopenharmony_ci  std::unique_ptr<Task> task = std::move(it->second);
1371cb0ef41Sopenharmony_ci  task_queue_.erase(it);
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  return task;
1401cb0ef41Sopenharmony_ci}
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_cistd::unique_ptr<Task>
1431cb0ef41Sopenharmony_ciDefaultForegroundTaskRunner::PopTaskFromDelayedQueueLocked(
1441cb0ef41Sopenharmony_ci    const base::MutexGuard&, Nestability* nestability) {
1451cb0ef41Sopenharmony_ci  if (delayed_task_queue_.empty()) return {};
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  double now = MonotonicallyIncreasingTime();
1481cb0ef41Sopenharmony_ci  const DelayedEntry& entry = delayed_task_queue_.top();
1491cb0ef41Sopenharmony_ci  if (entry.timeout_time > now) return {};
1501cb0ef41Sopenharmony_ci  // The const_cast here is necessary because there does not exist a clean way
1511cb0ef41Sopenharmony_ci  // to get a unique_ptr out of the priority queue. We provide the priority
1521cb0ef41Sopenharmony_ci  // queue with a custom comparison operator to make sure that the priority
1531cb0ef41Sopenharmony_ci  // queue does not access the unique_ptr. Therefore it should be safe to reset
1541cb0ef41Sopenharmony_ci  // the unique_ptr in the priority queue here. Note that the DelayedEntry is
1551cb0ef41Sopenharmony_ci  // removed from the priority_queue immediately afterwards.
1561cb0ef41Sopenharmony_ci  std::unique_ptr<Task> task = std::move(const_cast<DelayedEntry&>(entry).task);
1571cb0ef41Sopenharmony_ci  *nestability = entry.nestability;
1581cb0ef41Sopenharmony_ci  delayed_task_queue_.pop();
1591cb0ef41Sopenharmony_ci  return task;
1601cb0ef41Sopenharmony_ci}
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_cistd::unique_ptr<IdleTask> DefaultForegroundTaskRunner::PopTaskFromIdleQueue() {
1631cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
1641cb0ef41Sopenharmony_ci  if (idle_task_queue_.empty()) return {};
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci  std::unique_ptr<IdleTask> task = std::move(idle_task_queue_.front());
1671cb0ef41Sopenharmony_ci  idle_task_queue_.pop();
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  return task;
1701cb0ef41Sopenharmony_ci}
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_civoid DefaultForegroundTaskRunner::WaitForTaskLocked(const base::MutexGuard&) {
1731cb0ef41Sopenharmony_ci  if (!delayed_task_queue_.empty()) {
1741cb0ef41Sopenharmony_ci    double now = MonotonicallyIncreasingTime();
1751cb0ef41Sopenharmony_ci    const DelayedEntry& entry = delayed_task_queue_.top();
1761cb0ef41Sopenharmony_ci    double time_until_task = entry.timeout_time - now;
1771cb0ef41Sopenharmony_ci    if (time_until_task > 0) {
1781cb0ef41Sopenharmony_ci      bool woken_up = event_loop_control_.WaitFor(
1791cb0ef41Sopenharmony_ci          &lock_,
1801cb0ef41Sopenharmony_ci          base::TimeDelta::FromMicroseconds(
1811cb0ef41Sopenharmony_ci              time_until_task * base::TimeConstants::kMicrosecondsPerSecond));
1821cb0ef41Sopenharmony_ci      USE(woken_up);
1831cb0ef41Sopenharmony_ci    }
1841cb0ef41Sopenharmony_ci  } else {
1851cb0ef41Sopenharmony_ci    event_loop_control_.Wait(&lock_);
1861cb0ef41Sopenharmony_ci  }
1871cb0ef41Sopenharmony_ci}
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci}  // namespace platform
1901cb0ef41Sopenharmony_ci}  // namespace v8
191