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