blob: 338514cde4fdb8233306d725fd07b32aefd09b7c [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2022 The Chromium Authors
Abdias Dagbekpo6148d122022-08-23 17:36:392// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/task/thread_pool/delayed_priority_queue.h"
6
7#include <utility>
8
9#include "base/check_op.h"
10#include "base/memory/ptr_util.h"
11#include "base/stl_util.h"
12
13namespace base::internal {
14
15// A class combining a TaskSource and the delayed_sort_key that determines its
16// position in a DelayedPriorityQueue. Instances are only mutable via
17// take_task_source() which can only be called once and renders its instance
18// invalid after the call.
19class DelayedPriorityQueue::TaskSourceAndDelayedSortKey {
20 public:
21 TaskSourceAndDelayedSortKey() = default;
22 TaskSourceAndDelayedSortKey(scoped_refptr<TaskSource> task_source,
23 const TimeTicks& delayed_sort_key)
24 : task_source_(std::move(task_source)),
25 delayed_sort_key_(delayed_sort_key) {
26 DCHECK(task_source_);
27 }
28 TaskSourceAndDelayedSortKey(const TaskSourceAndDelayedSortKey&) = delete;
29 TaskSourceAndDelayedSortKey& operator=(const TaskSourceAndDelayedSortKey&) =
30 delete;
31
32 // Note: while |task_source_| should always be non-null post-move (i.e. we
33 // shouldn't be moving an invalid TaskSourceAndDelayedSortKey around), there
34 // can't be a DCHECK(task_source_) on moves as IntrusiveHeap moves elements on
35 // pop instead of overwriting them: resulting in the move of a
36 // TaskSourceAndDelayedSortKey with a null |task_source_| in
37 // Transaction::Pop()'s implementation.
38 TaskSourceAndDelayedSortKey(TaskSourceAndDelayedSortKey&& other) = default;
39 TaskSourceAndDelayedSortKey& operator=(TaskSourceAndDelayedSortKey&& other) =
40 default;
41
42 // Extracts |task_source_| from this object. This object is invalid after this
43 // call.
44 scoped_refptr<TaskSource> take_task_source() {
45 DCHECK(task_source_);
46 task_source_->ClearDelayedHeapHandle();
47 return std::move(task_source_);
48 }
49
50 // Compares this TaskSourceAndDelayedSortKey to |other| based on their
51 // respective |delayed_sort_key_|. Used for a max-heap.
52 bool operator<(const TaskSourceAndDelayedSortKey& other) const {
53 return delayed_sort_key_ < other.delayed_sort_key_;
54 }
55
56 // Required by IntrusiveHeap.
57 void SetHeapHandle(const HeapHandle& handle) {
58 DCHECK(task_source_);
59 task_source_->SetDelayedHeapHandle(handle);
60 }
61
62 // Required by IntrusiveHeap.
63 void ClearHeapHandle() {
64 // Ensure |task_source_| is not nullptr, which may be the case if
65 // take_task_source() was called before this.
Peter Kasting134ef9af2024-12-28 02:30:0966 if (task_source_) {
Abdias Dagbekpo6148d122022-08-23 17:36:3967 task_source_->ClearDelayedHeapHandle();
Peter Kasting134ef9af2024-12-28 02:30:0968 }
Abdias Dagbekpo6148d122022-08-23 17:36:3969 }
70
71 // Required by IntrusiveHeap.
72 HeapHandle GetHeapHandle() const {
Peter Kasting134ef9af2024-12-28 02:30:0973 if (task_source_) {
Abdias Dagbekpo6148d122022-08-23 17:36:3974 return task_source_->GetDelayedHeapHandle();
Peter Kasting134ef9af2024-12-28 02:30:0975 }
Abdias Dagbekpo6148d122022-08-23 17:36:3976 return HeapHandle::Invalid();
77 }
78
79 scoped_refptr<TaskSource> task_source() const { return task_source_; }
80
81 TimeTicks delayed_sort_key() const { return delayed_sort_key_; }
82
83 private:
84 scoped_refptr<TaskSource> task_source_;
85 TimeTicks delayed_sort_key_;
86};
87
88DelayedPriorityQueue::DelayedPriorityQueue() = default;
89
90DelayedPriorityQueue::~DelayedPriorityQueue() {
Peter Kasting134ef9af2024-12-28 02:30:0991 if (!is_flush_task_sources_on_destroy_enabled_) {
Abdias Dagbekpo6148d122022-08-23 17:36:3992 return;
Peter Kasting134ef9af2024-12-28 02:30:0993 }
Abdias Dagbekpo6148d122022-08-23 17:36:3994
95 while (!container_.empty()) {
96 auto task_source = PopTaskSource();
97 task_source->ClearForTesting(); // IN-TEST
98 }
99}
100
101DelayedPriorityQueue& DelayedPriorityQueue::operator=(
102 DelayedPriorityQueue&& other) = default;
103
104void DelayedPriorityQueue::Push(scoped_refptr<TaskSource> task_source,
105 TimeTicks task_source_delayed_sort_key) {
106 container_.insert(TaskSourceAndDelayedSortKey(std::move(task_source),
107 task_source_delayed_sort_key));
108}
109
110const TimeTicks DelayedPriorityQueue::PeekDelayedSortKey() const {
111 DCHECK(!IsEmpty());
112 return container_.top().delayed_sort_key();
113}
114
115scoped_refptr<TaskSource> DelayedPriorityQueue::PeekTaskSource() const {
116 DCHECK(!IsEmpty());
117
118 auto& task_source_and_delayed_sort_key = container_.top();
119 return task_source_and_delayed_sort_key.task_source();
120}
121
122scoped_refptr<TaskSource> DelayedPriorityQueue::PopTaskSource() {
123 DCHECK(!IsEmpty());
124
125 auto task_source_and_delayed_sort_key = container_.take_top();
126 scoped_refptr<TaskSource> task_source =
127 task_source_and_delayed_sort_key.take_task_source();
128 return task_source;
129}
130
131scoped_refptr<TaskSource> DelayedPriorityQueue::RemoveTaskSource(
132 scoped_refptr<TaskSource> task_source) {
Peter Kasting134ef9af2024-12-28 02:30:09133 if (IsEmpty()) {
Abdias Dagbekpo6148d122022-08-23 17:36:39134 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09135 }
Abdias Dagbekpo6148d122022-08-23 17:36:39136
137 const HeapHandle heap_handle = task_source->delayed_heap_handle();
Peter Kasting134ef9af2024-12-28 02:30:09138 if (!heap_handle.IsValid()) {
Abdias Dagbekpo6148d122022-08-23 17:36:39139 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09140 }
Abdias Dagbekpo6148d122022-08-23 17:36:39141
142 TaskSourceAndDelayedSortKey& task_source_and_delayed_sort_key =
143 const_cast<DelayedPriorityQueue::TaskSourceAndDelayedSortKey&>(
144 container_.at(heap_handle));
145 DCHECK_EQ(task_source_and_delayed_sort_key.task_source(), task_source);
146 task_source = task_source_and_delayed_sort_key.take_task_source();
147
148 container_.erase(heap_handle);
149 return task_source;
150}
151
152void DelayedPriorityQueue::UpdateDelayedSortKey(
153 scoped_refptr<TaskSource> task_source) {
Peter Kasting134ef9af2024-12-28 02:30:09154 if (IsEmpty()) {
Abdias Dagbekpo6148d122022-08-23 17:36:39155 return;
Peter Kasting134ef9af2024-12-28 02:30:09156 }
Abdias Dagbekpo6148d122022-08-23 17:36:39157
158 const HeapHandle heap_handle = task_source->delayed_heap_handle();
Peter Kasting134ef9af2024-12-28 02:30:09159 if (!heap_handle.IsValid()) {
Abdias Dagbekpo6148d122022-08-23 17:36:39160 return;
Peter Kasting134ef9af2024-12-28 02:30:09161 }
Abdias Dagbekpo6148d122022-08-23 17:36:39162
163 DCHECK_EQ(container_.at(heap_handle).task_source(), task_source);
164
165 task_source = const_cast<DelayedPriorityQueue::TaskSourceAndDelayedSortKey&>(
166 container_.at(heap_handle))
167 .take_task_source();
168 auto delayed_sort_key = task_source->GetDelayedSortKey();
169 container_.Replace(
170 heap_handle,
171 TaskSourceAndDelayedSortKey(std::move(task_source), delayed_sort_key));
172}
173
174bool DelayedPriorityQueue::IsEmpty() const {
175 return container_.empty();
176}
177
178size_t DelayedPriorityQueue::Size() const {
179 return container_.size();
180}
181
182void DelayedPriorityQueue::EnableFlushTaskSourcesOnDestroyForTesting() {
183 DCHECK(!is_flush_task_sources_on_destroy_enabled_);
184 is_flush_task_sources_on_destroy_enabled_ = true;
185}
186
187// Delayed tasks are ordered by latest_delayed_run_time(). The top task may
188// not be the first task eligible to run, but tasks will always become ripe
189// before their latest_delayed_run_time().
190bool DelayedPriorityQueue::DelayedPriorityQueueComparisonOperator::operator()(
191 const TaskSourceAndDelayedSortKey& lhs,
192 const TaskSourceAndDelayedSortKey& rhs) const {
193 return lhs.delayed_sort_key() > rhs.delayed_sort_key();
194}
195
196} // namespace base::internal