Line data Source code
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 :
14 60135 : DelayedTaskQueue::DelayedTaskQueue(TimeFunction time_function)
15 180405 : : time_function_(time_function) {}
16 :
17 114112 : DelayedTaskQueue::~DelayedTaskQueue() {
18 57056 : base::MutexGuard guard(&lock_);
19 : DCHECK(terminated_);
20 : DCHECK(task_queue_.empty());
21 57056 : }
22 :
23 0 : double DelayedTaskQueue::MonotonicallyIncreasingTime() {
24 86 : return time_function_();
25 : }
26 :
27 1357441 : void DelayedTaskQueue::Append(std::unique_ptr<Task> task) {
28 1357441 : base::MutexGuard guard(&lock_);
29 : DCHECK(!terminated_);
30 : task_queue_.push(std::move(task));
31 1357441 : queues_condition_var_.NotifyOne();
32 1357441 : }
33 :
34 35 : void DelayedTaskQueue::AppendDelayed(std::unique_ptr<Task> task,
35 : double delay_in_seconds) {
36 : DCHECK_GE(delay_in_seconds, 0.0);
37 35 : double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
38 : {
39 35 : base::MutexGuard guard(&lock_);
40 : DCHECK(!terminated_);
41 : delayed_task_queue_.emplace(deadline, std::move(task));
42 35 : queues_condition_var_.NotifyOne();
43 : }
44 35 : }
45 :
46 1775651 : std::unique_ptr<Task> DelayedTaskQueue::GetNext() {
47 1775651 : base::MutexGuard guard(&lock_);
48 : for (;;) {
49 : // Move delayed tasks that have hit their deadline to the main queue.
50 3305140 : std::unique_ptr<Task> task = PopTaskFromDelayedQueue();
51 3305208 : while (task) {
52 : task_queue_.push(std::move(task));
53 68 : task = PopTaskFromDelayedQueue();
54 : }
55 3305140 : if (!task_queue_.empty()) {
56 : std::unique_ptr<Task> result = std::move(task_queue_.front());
57 : task_queue_.pop();
58 : return result;
59 : }
60 :
61 1947665 : if (terminated_) {
62 399353 : queues_condition_var_.NotifyAll();
63 : return nullptr;
64 : }
65 :
66 1548312 : if (task_queue_.empty() && !delayed_task_queue_.empty()) {
67 : // Wait for the next delayed task or a newly posted task.
68 : double now = MonotonicallyIncreasingTime();
69 4 : double wait_in_seconds = delayed_task_queue_.begin()->first - now;
70 : base::TimeDelta wait_delta = base::TimeDelta::FromMicroseconds(
71 4 : 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 4 : bool notified = queues_condition_var_.WaitFor(&lock_, wait_delta);
77 : USE(notified);
78 : } else {
79 1548308 : 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 |time_function_|. Returns nullptr if no such task exists.
86 3305174 : std::unique_ptr<Task> DelayedTaskQueue::PopTaskFromDelayedQueue() {
87 3305174 : if (delayed_task_queue_.empty()) return nullptr;
88 :
89 : double now = MonotonicallyIncreasingTime();
90 :
91 : auto it = delayed_task_queue_.begin();
92 47 : if (it->first > now) return nullptr;
93 :
94 : std::unique_ptr<Task> result = std::move(it->second);
95 : delayed_task_queue_.erase(it);
96 : return result;
97 : }
98 :
99 57056 : void DelayedTaskQueue::Terminate() {
100 57056 : base::MutexGuard guard(&lock_);
101 : DCHECK(!terminated_);
102 57056 : terminated_ = true;
103 57056 : queues_condition_var_.NotifyAll();
104 57056 : }
105 :
106 : } // namespace platform
107 : } // namespace v8
|