11cb0ef41Sopenharmony_ci// Copyright 2019 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/delayed-task-queue.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "include/v8-platform.h"
81cb0ef41Sopenharmony_ci#include "src/base/logging.h"
91cb0ef41Sopenharmony_ci#include "src/base/platform/time.h"
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_cinamespace v8 {
121cb0ef41Sopenharmony_cinamespace platform {
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciDelayedTaskQueue::DelayedTaskQueue(TimeFunction time_function)
151cb0ef41Sopenharmony_ci    : time_function_(time_function) {}
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciDelayedTaskQueue::~DelayedTaskQueue() {
181cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
191cb0ef41Sopenharmony_ci  DCHECK(terminated_);
201cb0ef41Sopenharmony_ci  DCHECK(task_queue_.empty());
211cb0ef41Sopenharmony_ci}
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cidouble DelayedTaskQueue::MonotonicallyIncreasingTime() {
241cb0ef41Sopenharmony_ci  return time_function_();
251cb0ef41Sopenharmony_ci}
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_civoid DelayedTaskQueue::Append(std::unique_ptr<Task> task) {
281cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
291cb0ef41Sopenharmony_ci  DCHECK(!terminated_);
301cb0ef41Sopenharmony_ci  task_queue_.push(std::move(task));
311cb0ef41Sopenharmony_ci  queues_condition_var_.NotifyOne();
321cb0ef41Sopenharmony_ci}
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_civoid DelayedTaskQueue::AppendDelayed(std::unique_ptr<Task> task,
351cb0ef41Sopenharmony_ci                                     double delay_in_seconds) {
361cb0ef41Sopenharmony_ci  DCHECK_GE(delay_in_seconds, 0.0);
371cb0ef41Sopenharmony_ci  double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
381cb0ef41Sopenharmony_ci  {
391cb0ef41Sopenharmony_ci    base::MutexGuard guard(&lock_);
401cb0ef41Sopenharmony_ci    DCHECK(!terminated_);
411cb0ef41Sopenharmony_ci    delayed_task_queue_.emplace(deadline, std::move(task));
421cb0ef41Sopenharmony_ci    queues_condition_var_.NotifyOne();
431cb0ef41Sopenharmony_ci  }
441cb0ef41Sopenharmony_ci}
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_cistd::unique_ptr<Task> DelayedTaskQueue::GetNext() {
471cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
481cb0ef41Sopenharmony_ci  for (;;) {
491cb0ef41Sopenharmony_ci    // Move delayed tasks that have hit their deadline to the main queue.
501cb0ef41Sopenharmony_ci    double now = MonotonicallyIncreasingTime();
511cb0ef41Sopenharmony_ci    std::unique_ptr<Task> task = PopTaskFromDelayedQueue(now);
521cb0ef41Sopenharmony_ci    while (task) {
531cb0ef41Sopenharmony_ci      task_queue_.push(std::move(task));
541cb0ef41Sopenharmony_ci      task = PopTaskFromDelayedQueue(now);
551cb0ef41Sopenharmony_ci    }
561cb0ef41Sopenharmony_ci    if (!task_queue_.empty()) {
571cb0ef41Sopenharmony_ci      std::unique_ptr<Task> result = std::move(task_queue_.front());
581cb0ef41Sopenharmony_ci      task_queue_.pop();
591cb0ef41Sopenharmony_ci      return result;
601cb0ef41Sopenharmony_ci    }
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci    if (terminated_) {
631cb0ef41Sopenharmony_ci      queues_condition_var_.NotifyAll();
641cb0ef41Sopenharmony_ci      return nullptr;
651cb0ef41Sopenharmony_ci    }
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci    if (task_queue_.empty() && !delayed_task_queue_.empty()) {
681cb0ef41Sopenharmony_ci      // Wait for the next delayed task or a newly posted task.
691cb0ef41Sopenharmony_ci      double wait_in_seconds = delayed_task_queue_.begin()->first - now;
701cb0ef41Sopenharmony_ci      base::TimeDelta wait_delta = base::TimeDelta::FromMicroseconds(
711cb0ef41Sopenharmony_ci          base::TimeConstants::kMicrosecondsPerSecond * wait_in_seconds);
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci      // WaitFor unfortunately doesn't care about our fake time and will wait
741cb0ef41Sopenharmony_ci      // the 'real' amount of time, based on whatever clock the system call
751cb0ef41Sopenharmony_ci      // uses.
761cb0ef41Sopenharmony_ci      bool notified = queues_condition_var_.WaitFor(&lock_, wait_delta);
771cb0ef41Sopenharmony_ci      USE(notified);
781cb0ef41Sopenharmony_ci    } else {
791cb0ef41Sopenharmony_ci      queues_condition_var_.Wait(&lock_);
801cb0ef41Sopenharmony_ci    }
811cb0ef41Sopenharmony_ci  }
821cb0ef41Sopenharmony_ci}
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci// Gets the next task from the delayed queue for which the deadline has passed
851cb0ef41Sopenharmony_ci// according to |now|. Returns nullptr if no such task exists.
861cb0ef41Sopenharmony_cistd::unique_ptr<Task> DelayedTaskQueue::PopTaskFromDelayedQueue(double now) {
871cb0ef41Sopenharmony_ci  if (delayed_task_queue_.empty()) return nullptr;
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  auto it = delayed_task_queue_.begin();
901cb0ef41Sopenharmony_ci  if (it->first > now) return nullptr;
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  std::unique_ptr<Task> result = std::move(it->second);
931cb0ef41Sopenharmony_ci  delayed_task_queue_.erase(it);
941cb0ef41Sopenharmony_ci  return result;
951cb0ef41Sopenharmony_ci}
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_civoid DelayedTaskQueue::Terminate() {
981cb0ef41Sopenharmony_ci  base::MutexGuard guard(&lock_);
991cb0ef41Sopenharmony_ci  DCHECK(!terminated_);
1001cb0ef41Sopenharmony_ci  terminated_ = true;
1011cb0ef41Sopenharmony_ci  queues_condition_var_.NotifyAll();
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci}  // namespace platform
1051cb0ef41Sopenharmony_ci}  // namespace v8
106