xref: /aosp_15_r20/external/cronet/base/task/thread_pool/delayed_priority_queue.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 The Chromium Authors
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 "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 
13 namespace 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.
19 class DelayedPriorityQueue::TaskSourceAndDelayedSortKey {
20  public:
21   TaskSourceAndDelayedSortKey() = default;
TaskSourceAndDelayedSortKey(scoped_refptr<TaskSource> task_source,const TimeTicks & delayed_sort_key)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.
take_task_source()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.
operator <(const TaskSourceAndDelayedSortKey & other) const52   bool operator<(const TaskSourceAndDelayedSortKey& other) const {
53     return delayed_sort_key_ < other.delayed_sort_key_;
54   }
55 
56   // Required by IntrusiveHeap.
SetHeapHandle(const HeapHandle & handle)57   void SetHeapHandle(const HeapHandle& handle) {
58     DCHECK(task_source_);
59     task_source_->SetDelayedHeapHandle(handle);
60   }
61 
62   // Required by IntrusiveHeap.
ClearHeapHandle()63   void ClearHeapHandle() {
64     // Ensure |task_source_| is not nullptr, which may be the case if
65     // take_task_source() was called before this.
66     if (task_source_)
67       task_source_->ClearDelayedHeapHandle();
68   }
69 
70   // Required by IntrusiveHeap.
GetHeapHandle() const71   HeapHandle GetHeapHandle() const {
72     if (task_source_)
73       return task_source_->GetDelayedHeapHandle();
74     return HeapHandle::Invalid();
75   }
76 
task_source() const77   scoped_refptr<TaskSource> task_source() const { return task_source_; }
78 
delayed_sort_key() const79   TimeTicks delayed_sort_key() const { return delayed_sort_key_; }
80 
81  private:
82   scoped_refptr<TaskSource> task_source_;
83   TimeTicks delayed_sort_key_;
84 };
85 
86 DelayedPriorityQueue::DelayedPriorityQueue() = default;
87 
~DelayedPriorityQueue()88 DelayedPriorityQueue::~DelayedPriorityQueue() {
89   if (!is_flush_task_sources_on_destroy_enabled_)
90     return;
91 
92   while (!container_.empty()) {
93     auto task_source = PopTaskSource();
94     task_source->ClearForTesting();  // IN-TEST
95   }
96 }
97 
98 DelayedPriorityQueue& DelayedPriorityQueue::operator=(
99     DelayedPriorityQueue&& other) = default;
100 
Push(scoped_refptr<TaskSource> task_source,TimeTicks task_source_delayed_sort_key)101 void DelayedPriorityQueue::Push(scoped_refptr<TaskSource> task_source,
102                                 TimeTicks task_source_delayed_sort_key) {
103   container_.insert(TaskSourceAndDelayedSortKey(std::move(task_source),
104                                                 task_source_delayed_sort_key));
105 }
106 
PeekDelayedSortKey() const107 const TimeTicks DelayedPriorityQueue::PeekDelayedSortKey() const {
108   DCHECK(!IsEmpty());
109   return container_.top().delayed_sort_key();
110 }
111 
PeekTaskSource() const112 scoped_refptr<TaskSource> DelayedPriorityQueue::PeekTaskSource() const {
113   DCHECK(!IsEmpty());
114 
115   auto& task_source_and_delayed_sort_key = container_.top();
116   return task_source_and_delayed_sort_key.task_source();
117 }
118 
PopTaskSource()119 scoped_refptr<TaskSource> DelayedPriorityQueue::PopTaskSource() {
120   DCHECK(!IsEmpty());
121 
122   auto task_source_and_delayed_sort_key = container_.take_top();
123   scoped_refptr<TaskSource> task_source =
124       task_source_and_delayed_sort_key.take_task_source();
125   return task_source;
126 }
127 
RemoveTaskSource(scoped_refptr<TaskSource> task_source)128 scoped_refptr<TaskSource> DelayedPriorityQueue::RemoveTaskSource(
129     scoped_refptr<TaskSource> task_source) {
130   if (IsEmpty())
131     return nullptr;
132 
133   const HeapHandle heap_handle = task_source->delayed_heap_handle();
134   if (!heap_handle.IsValid())
135     return nullptr;
136 
137   TaskSourceAndDelayedSortKey& task_source_and_delayed_sort_key =
138       const_cast<DelayedPriorityQueue::TaskSourceAndDelayedSortKey&>(
139           container_.at(heap_handle));
140   DCHECK_EQ(task_source_and_delayed_sort_key.task_source(), task_source);
141   task_source = task_source_and_delayed_sort_key.take_task_source();
142 
143   container_.erase(heap_handle);
144   return task_source;
145 }
146 
UpdateDelayedSortKey(scoped_refptr<TaskSource> task_source)147 void DelayedPriorityQueue::UpdateDelayedSortKey(
148     scoped_refptr<TaskSource> task_source) {
149   if (IsEmpty())
150     return;
151 
152   const HeapHandle heap_handle = task_source->delayed_heap_handle();
153   if (!heap_handle.IsValid())
154     return;
155 
156   DCHECK_EQ(container_.at(heap_handle).task_source(), task_source);
157 
158   task_source = const_cast<DelayedPriorityQueue::TaskSourceAndDelayedSortKey&>(
159                     container_.at(heap_handle))
160                     .take_task_source();
161   auto delayed_sort_key = task_source->GetDelayedSortKey();
162   container_.Replace(
163       heap_handle,
164       TaskSourceAndDelayedSortKey(std::move(task_source), delayed_sort_key));
165 }
166 
IsEmpty() const167 bool DelayedPriorityQueue::IsEmpty() const {
168   return container_.empty();
169 }
170 
Size() const171 size_t DelayedPriorityQueue::Size() const {
172   return container_.size();
173 }
174 
EnableFlushTaskSourcesOnDestroyForTesting()175 void DelayedPriorityQueue::EnableFlushTaskSourcesOnDestroyForTesting() {
176   DCHECK(!is_flush_task_sources_on_destroy_enabled_);
177   is_flush_task_sources_on_destroy_enabled_ = true;
178 }
179 
180 // Delayed tasks are ordered by latest_delayed_run_time(). The top task may
181 // not be the first task eligible to run, but tasks will always become ripe
182 // before their latest_delayed_run_time().
operator ()(const TaskSourceAndDelayedSortKey & lhs,const TaskSourceAndDelayedSortKey & rhs) const183 bool DelayedPriorityQueue::DelayedPriorityQueueComparisonOperator::operator()(
184     const TaskSourceAndDelayedSortKey& lhs,
185     const TaskSourceAndDelayedSortKey& rhs) const {
186   return lhs.delayed_sort_key() > rhs.delayed_sort_key();
187 }
188 
189 }  // namespace base::internal
190