• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/libplatform/delayed-task-queue.h"
6 
7 #include "include/v8-platform.h"
8 #include "src/base/logging.h"
9 #include "src/base/platform/time.h"
10 
11 namespace v8 {
12 namespace platform {
13 
DelayedTaskQueue(TimeFunction time_function)14 DelayedTaskQueue::DelayedTaskQueue(TimeFunction time_function)
15     : time_function_(time_function) {}
16 
~DelayedTaskQueue()17 DelayedTaskQueue::~DelayedTaskQueue() {
18   base::MutexGuard guard(&lock_);
19   DCHECK(terminated_);
20   DCHECK(task_queue_.empty());
21 }
22 
MonotonicallyIncreasingTime()23 double DelayedTaskQueue::MonotonicallyIncreasingTime() {
24   return time_function_();
25 }
26 
Append(std::unique_ptr<Task> task)27 void DelayedTaskQueue::Append(std::unique_ptr<Task> task) {
28   base::MutexGuard guard(&lock_);
29   DCHECK(!terminated_);
30   task_queue_.push(std::move(task));
31   queues_condition_var_.NotifyOne();
32 }
33 
AppendDelayed(std::unique_ptr<Task> task,double delay_in_seconds)34 void DelayedTaskQueue::AppendDelayed(std::unique_ptr<Task> task,
35                                      double delay_in_seconds) {
36   DCHECK_GE(delay_in_seconds, 0.0);
37   double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
38   {
39     base::MutexGuard guard(&lock_);
40     DCHECK(!terminated_);
41     delayed_task_queue_.emplace(deadline, std::move(task));
42     queues_condition_var_.NotifyOne();
43   }
44 }
45 
GetNext()46 std::unique_ptr<Task> DelayedTaskQueue::GetNext() {
47   base::MutexGuard guard(&lock_);
48   for (;;) {
49     // Move delayed tasks that have hit their deadline to the main queue.
50     double now = MonotonicallyIncreasingTime();
51     std::unique_ptr<Task> task = PopTaskFromDelayedQueue(now);
52     while (task) {
53       task_queue_.push(std::move(task));
54       task = PopTaskFromDelayedQueue(now);
55     }
56     if (!task_queue_.empty()) {
57       std::unique_ptr<Task> result = std::move(task_queue_.front());
58       task_queue_.pop();
59       return result;
60     }
61 
62     if (terminated_) {
63       queues_condition_var_.NotifyAll();
64       return nullptr;
65     }
66 
67     if (task_queue_.empty() && !delayed_task_queue_.empty()) {
68       // Wait for the next delayed task or a newly posted task.
69       double wait_in_seconds = delayed_task_queue_.begin()->first - now;
70       base::TimeDelta wait_delta = base::TimeDelta::FromMicroseconds(
71           base::TimeConstants::kMicrosecondsPerSecond * wait_in_seconds);
72 
73       // WaitFor unfortunately doesn't care about our fake time and will wait
74       // the 'real' amount of time, based on whatever clock the system call
75       // uses.
76       bool notified = queues_condition_var_.WaitFor(&lock_, wait_delta);
77       USE(notified);
78     } else {
79       queues_condition_var_.Wait(&lock_);
80     }
81   }
82 }
83 
84 // Gets the next task from the delayed queue for which the deadline has passed
85 // according to |now|. Returns nullptr if no such task exists.
PopTaskFromDelayedQueue(double now)86 std::unique_ptr<Task> DelayedTaskQueue::PopTaskFromDelayedQueue(double now) {
87   if (delayed_task_queue_.empty()) return nullptr;
88 
89   auto it = delayed_task_queue_.begin();
90   if (it->first > now) return nullptr;
91 
92   std::unique_ptr<Task> result = std::move(it->second);
93   delayed_task_queue_.erase(it);
94   return result;
95 }
96 
Terminate()97 void DelayedTaskQueue::Terminate() {
98   base::MutexGuard guard(&lock_);
99   DCHECK(!terminated_);
100   terminated_ = true;
101   queues_condition_var_.NotifyAll();
102 }
103 
104 }  // namespace platform
105 }  // namespace v8
106