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 61029 : DelayedTaskQueue::DelayedTaskQueue(TimeFunction time_function)
15 183087 : : time_function_(time_function) {}
16 :
17 115872 : DelayedTaskQueue::~DelayedTaskQueue() {
18 57936 : base::MutexGuard guard(&lock_);
19 : DCHECK(terminated_);
20 : DCHECK(task_queue_.empty());
21 57936 : }
22 :
23 0 : double DelayedTaskQueue::MonotonicallyIncreasingTime() {
24 4079761 : return time_function_();
25 : }
26 :
27 1771292 : void DelayedTaskQueue::Append(std::unique_ptr<Task> task) {
28 1771292 : base::MutexGuard guard(&lock_);
29 : DCHECK(!terminated_);
30 : task_queue_.push(std::move(task));
31 1771292 : queues_condition_var_.NotifyOne();
32 1771292 : }
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 2196409 : std::unique_ptr<Task> DelayedTaskQueue::GetNext() {
47 2196409 : base::MutexGuard guard(&lock_);
48 : for (;;) {
49 : // Move delayed tasks that have hit their deadline to the main queue.
50 : double now = MonotonicallyIncreasingTime();
51 4079726 : std::unique_ptr<Task> task = PopTaskFromDelayedQueue(now);
52 4079794 : while (task) {
53 : task_queue_.push(std::move(task));
54 68 : task = PopTaskFromDelayedQueue(now);
55 : }
56 4079726 : 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 2308400 : if (terminated_) {
63 405513 : queues_condition_var_.NotifyAll();
64 : return nullptr;
65 : }
66 :
67 1902887 : if (task_queue_.empty() && !delayed_task_queue_.empty()) {
68 : // Wait for the next delayed task or a newly posted task.
69 1 : double wait_in_seconds = delayed_task_queue_.begin()->first - now;
70 : base::TimeDelta wait_delta = base::TimeDelta::FromMicroseconds(
71 1 : 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 1 : bool notified = queues_condition_var_.WaitFor(&lock_, wait_delta);
77 : USE(notified);
78 : } else {
79 1902886 : 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.
86 4079760 : std::unique_ptr<Task> DelayedTaskQueue::PopTaskFromDelayedQueue(double now) {
87 4079760 : if (delayed_task_queue_.empty()) return nullptr;
88 :
89 : auto it = delayed_task_queue_.begin();
90 44 : 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 :
97 57936 : void DelayedTaskQueue::Terminate() {
98 57936 : base::MutexGuard guard(&lock_);
99 : DCHECK(!terminated_);
100 57936 : terminated_ = true;
101 57936 : queues_condition_var_.NotifyAll();
102 57936 : }
103 :
104 : } // namespace platform
105 : } // namespace v8
|