xref: /aosp_15_r20/external/cronet/base/task/thread_pool/sequence.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2016 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_TASK_THREAD_POOL_SEQUENCE_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_TASK_THREAD_POOL_SEQUENCE_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/containers/intrusive_heap.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/containers/queue.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/sequence_token.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/task/task_traits.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool/pooled_parallel_task_runner.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool/task.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool/task_source.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool/task_source_sort_key.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/thread_annotations.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/threading/sequence_local_storage_map.h"
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker namespace base {
23*6777b538SAndroid Build Coastguard Worker namespace internal {
24*6777b538SAndroid Build Coastguard Worker 
25*6777b538SAndroid Build Coastguard Worker // A Sequence is intended to hold delayed tasks and immediate tasks.
26*6777b538SAndroid Build Coastguard Worker // Delayed tasks are held in a prority_queue until they are ripe and
27*6777b538SAndroid Build Coastguard Worker // immediate tasks in a simple fifo queue.
28*6777b538SAndroid Build Coastguard Worker // When Sequence::TakeTask is called, we select the next appropriate task
29*6777b538SAndroid Build Coastguard Worker // from both queues and return it.
30*6777b538SAndroid Build Coastguard Worker // Each queue holds slots each containing up to a single Task that must be
31*6777b538SAndroid Build Coastguard Worker // executed in posting/runtime order.
32*6777b538SAndroid Build Coastguard Worker //
33*6777b538SAndroid Build Coastguard Worker // In comments below, an "empty Sequence" is a Sequence with no slot.
34*6777b538SAndroid Build Coastguard Worker //
35*6777b538SAndroid Build Coastguard Worker // Note: there is a known refcounted-ownership cycle in the Scheduler
36*6777b538SAndroid Build Coastguard Worker // architecture: Sequence -> Task -> TaskRunner -> Sequence -> ...
37*6777b538SAndroid Build Coastguard Worker // This is okay so long as the other owners of Sequence (PriorityQueue and
38*6777b538SAndroid Build Coastguard Worker // WorkerThread in alternation and
39*6777b538SAndroid Build Coastguard Worker // ThreadGroup::WorkerThreadDelegateImpl::GetWork()
40*6777b538SAndroid Build Coastguard Worker // temporarily) keep running it (and taking Tasks from it as a result). A
41*6777b538SAndroid Build Coastguard Worker // dangling reference cycle would only occur should they release their reference
42*6777b538SAndroid Build Coastguard Worker // to it while it's not empty. In other words, it is only correct for them to
43*6777b538SAndroid Build Coastguard Worker // release it after PopTask() returns false to indicate it was made empty by
44*6777b538SAndroid Build Coastguard Worker // that call (in which case the next PushImmediateTask() will return true to
45*6777b538SAndroid Build Coastguard Worker // indicate to the caller that the Sequence should be re-enqueued for
46*6777b538SAndroid Build Coastguard Worker // execution). This class is thread-safe.
47*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT Sequence : public TaskSource {
48*6777b538SAndroid Build Coastguard Worker  public:
49*6777b538SAndroid Build Coastguard Worker   // A Transaction can perform multiple operations atomically on a
50*6777b538SAndroid Build Coastguard Worker   // Sequence. While a Transaction is alive, it is guaranteed that nothing
51*6777b538SAndroid Build Coastguard Worker   // else will access the Sequence; the Sequence's lock is held for the
52*6777b538SAndroid Build Coastguard Worker   // lifetime of the Transaction.
53*6777b538SAndroid Build Coastguard Worker   class BASE_EXPORT Transaction : public TaskSource::Transaction {
54*6777b538SAndroid Build Coastguard Worker    public:
55*6777b538SAndroid Build Coastguard Worker     Transaction(Transaction&& other);
56*6777b538SAndroid Build Coastguard Worker     Transaction(const Transaction&) = delete;
57*6777b538SAndroid Build Coastguard Worker     Transaction& operator=(const Transaction&) = delete;
58*6777b538SAndroid Build Coastguard Worker     ~Transaction();
59*6777b538SAndroid Build Coastguard Worker 
60*6777b538SAndroid Build Coastguard Worker     // Returns true if the sequence must be added to the immediate queue after
61*6777b538SAndroid Build Coastguard Worker     // receiving a new immediate Task in order to be scheduled. If the caller
62*6777b538SAndroid Build Coastguard Worker     // doesn't want the sequence to be scheduled, it may not add the sequence to
63*6777b538SAndroid Build Coastguard Worker     // the immediate queue even if this returns true.
64*6777b538SAndroid Build Coastguard Worker     bool WillPushImmediateTask();
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker     // Adds immediate |task| to the end of this sequence.
67*6777b538SAndroid Build Coastguard Worker     void PushImmediateTask(Task task);
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker     // Adds a delayed |task| in this sequence, and returns true if the sequence
70*6777b538SAndroid Build Coastguard Worker     // needs to be re-enqueued in the delayed queue as a result of this
71*6777b538SAndroid Build Coastguard Worker     // sequence's delayed sort key changing.
72*6777b538SAndroid Build Coastguard Worker     bool PushDelayedTask(Task task);
73*6777b538SAndroid Build Coastguard Worker 
sequence()74*6777b538SAndroid Build Coastguard Worker     Sequence* sequence() const { return static_cast<Sequence*>(task_source()); }
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker    private:
77*6777b538SAndroid Build Coastguard Worker     friend class Sequence;
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker     explicit Transaction(Sequence* sequence);
80*6777b538SAndroid Build Coastguard Worker   };
81*6777b538SAndroid Build Coastguard Worker 
82*6777b538SAndroid Build Coastguard Worker   // |traits| is metadata that applies to all Tasks in the Sequence.
83*6777b538SAndroid Build Coastguard Worker   // |task_runner| is a reference to the TaskRunner feeding this TaskSource.
84*6777b538SAndroid Build Coastguard Worker   // |task_runner| can be nullptr only for tasks with no TaskRunner, in which
85*6777b538SAndroid Build Coastguard Worker   // case |execution_mode| must be kParallel. Otherwise, |execution_mode| is the
86*6777b538SAndroid Build Coastguard Worker   // execution mode of |task_runner|.
87*6777b538SAndroid Build Coastguard Worker   Sequence(const TaskTraits& traits,
88*6777b538SAndroid Build Coastguard Worker            SequencedTaskRunner* task_runner,
89*6777b538SAndroid Build Coastguard Worker            TaskSourceExecutionMode execution_mode);
90*6777b538SAndroid Build Coastguard Worker   Sequence(const Sequence&) = delete;
91*6777b538SAndroid Build Coastguard Worker   Sequence& operator=(const Sequence&) = delete;
92*6777b538SAndroid Build Coastguard Worker 
93*6777b538SAndroid Build Coastguard Worker   // Begins a Transaction. This method cannot be called on a thread which has an
94*6777b538SAndroid Build Coastguard Worker   // active Sequence::Transaction.
95*6777b538SAndroid Build Coastguard Worker   [[nodiscard]] Transaction BeginTransaction();
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker   // TaskSource:
98*6777b538SAndroid Build Coastguard Worker   ExecutionEnvironment GetExecutionEnvironment() override;
99*6777b538SAndroid Build Coastguard Worker   size_t GetRemainingConcurrency() const override;
100*6777b538SAndroid Build Coastguard Worker   TaskSourceSortKey GetSortKey() const override;
101*6777b538SAndroid Build Coastguard Worker   TimeTicks GetDelayedSortKey() const override;
102*6777b538SAndroid Build Coastguard Worker 
103*6777b538SAndroid Build Coastguard Worker   // Returns a token that uniquely identifies this Sequence.
token()104*6777b538SAndroid Build Coastguard Worker   const SequenceToken& token() const { return token_; }
105*6777b538SAndroid Build Coastguard Worker 
sequence_local_storage()106*6777b538SAndroid Build Coastguard Worker   SequenceLocalStorageMap* sequence_local_storage() {
107*6777b538SAndroid Build Coastguard Worker     return &sequence_local_storage_;
108*6777b538SAndroid Build Coastguard Worker   }
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker   bool OnBecomeReady() override;
111*6777b538SAndroid Build Coastguard Worker 
has_worker_for_testing()112*6777b538SAndroid Build Coastguard Worker   bool has_worker_for_testing() const NO_THREAD_SAFETY_ANALYSIS {
113*6777b538SAndroid Build Coastguard Worker     return has_worker_;
114*6777b538SAndroid Build Coastguard Worker   }
is_immediate_for_testing()115*6777b538SAndroid Build Coastguard Worker   bool is_immediate_for_testing() const { return is_immediate_; }
IsEmptyForTesting()116*6777b538SAndroid Build Coastguard Worker   bool IsEmptyForTesting() const NO_THREAD_SAFETY_ANALYSIS { return IsEmpty(); }
117*6777b538SAndroid Build Coastguard Worker 
118*6777b538SAndroid Build Coastguard Worker   // A reference to TaskRunner is only retained between
119*6777b538SAndroid Build Coastguard Worker   // PushImmediateTask()/PushDelayedTask() and when DidProcessTask() returns
120*6777b538SAndroid Build Coastguard Worker   // false, guaranteeing it is safe to dereference this pointer. Otherwise, the
121*6777b538SAndroid Build Coastguard Worker   // caller should guarantee such TaskRunner still exists before dereferencing.
task_runner()122*6777b538SAndroid Build Coastguard Worker   SequencedTaskRunner* task_runner() const { return task_runner_; }
123*6777b538SAndroid Build Coastguard Worker 
124*6777b538SAndroid Build Coastguard Worker  private:
125*6777b538SAndroid Build Coastguard Worker   ~Sequence() override;
126*6777b538SAndroid Build Coastguard Worker 
127*6777b538SAndroid Build Coastguard Worker   struct DelayedTaskGreater {
128*6777b538SAndroid Build Coastguard Worker     bool operator()(const Task& lhs, const Task& rhs) const;
129*6777b538SAndroid Build Coastguard Worker   };
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker   // TaskSource:
132*6777b538SAndroid Build Coastguard Worker   RunStatus WillRunTask() override;
133*6777b538SAndroid Build Coastguard Worker   Task TakeTask(TaskSource::Transaction* transaction) override;
134*6777b538SAndroid Build Coastguard Worker   std::optional<Task> Clear(TaskSource::Transaction* transaction) override;
135*6777b538SAndroid Build Coastguard Worker   bool DidProcessTask(TaskSource::Transaction* transaction) override;
136*6777b538SAndroid Build Coastguard Worker   bool WillReEnqueue(TimeTicks now,
137*6777b538SAndroid Build Coastguard Worker                      TaskSource::Transaction* transaction) override;
138*6777b538SAndroid Build Coastguard Worker 
139*6777b538SAndroid Build Coastguard Worker   // Returns true if the delayed task to be posted will cause the delayed sort
140*6777b538SAndroid Build Coastguard Worker   // key to change.
141*6777b538SAndroid Build Coastguard Worker   bool DelayedSortKeyWillChange(const Task& delayed_task) const
142*6777b538SAndroid Build Coastguard Worker       EXCLUSIVE_LOCKS_REQUIRED(lock_);
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker   // Selects the earliest task to run, either from immediate or
145*6777b538SAndroid Build Coastguard Worker   // delayed queue and return it.
146*6777b538SAndroid Build Coastguard Worker   // Expects this sequence to have at least one task that can run
147*6777b538SAndroid Build Coastguard Worker   // immediately.
148*6777b538SAndroid Build Coastguard Worker   Task TakeEarliestTask() EXCLUSIVE_LOCKS_REQUIRED(lock_);
149*6777b538SAndroid Build Coastguard Worker 
150*6777b538SAndroid Build Coastguard Worker   // Get and return next task from immediate queue
151*6777b538SAndroid Build Coastguard Worker   Task TakeNextImmediateTask() EXCLUSIVE_LOCKS_REQUIRED(lock_);
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker   // Update the next earliest/latest ready time.
154*6777b538SAndroid Build Coastguard Worker   void UpdateReadyTimes() EXCLUSIVE_LOCKS_REQUIRED(lock_);
155*6777b538SAndroid Build Coastguard Worker 
156*6777b538SAndroid Build Coastguard Worker   // Returns true if there are immediate tasks
157*6777b538SAndroid Build Coastguard Worker   bool HasImmediateTasks() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
158*6777b538SAndroid Build Coastguard Worker 
159*6777b538SAndroid Build Coastguard Worker   // Returns true if tasks ready to be executed
160*6777b538SAndroid Build Coastguard Worker   bool HasReadyTasks(TimeTicks now) const override;
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker   bool IsEmpty() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker   // Releases reference to TaskRunner.
165*6777b538SAndroid Build Coastguard Worker   void ReleaseTaskRunner();
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker   const SequenceToken token_ = SequenceToken::Create();
168*6777b538SAndroid Build Coastguard Worker 
169*6777b538SAndroid Build Coastguard Worker   // A pointer to the TaskRunner that posts to this TaskSource, if any. The
170*6777b538SAndroid Build Coastguard Worker   // derived class is responsible for calling AddRef() when a TaskSource from
171*6777b538SAndroid Build Coastguard Worker   // which no Task is executing becomes non-empty and Release() when
172*6777b538SAndroid Build Coastguard Worker   // it becomes empty again (e.g. when DidProcessTask() returns false).
173*6777b538SAndroid Build Coastguard Worker   //
174*6777b538SAndroid Build Coastguard Worker   // In practise, this pointer is going to become dangling. See task_runner()
175*6777b538SAndroid Build Coastguard Worker   // comment.
176*6777b538SAndroid Build Coastguard Worker   raw_ptr<SequencedTaskRunner, DisableDanglingPtrDetection> task_runner_;
177*6777b538SAndroid Build Coastguard Worker 
178*6777b538SAndroid Build Coastguard Worker   // Queues of tasks to execute.
179*6777b538SAndroid Build Coastguard Worker   base::queue<Task> queue_ GUARDED_BY(lock_);
180*6777b538SAndroid Build Coastguard Worker   base::IntrusiveHeap<Task, DelayedTaskGreater> delayed_queue_
181*6777b538SAndroid Build Coastguard Worker       GUARDED_BY(lock_);
182*6777b538SAndroid Build Coastguard Worker 
183*6777b538SAndroid Build Coastguard Worker   // Caches the latest/earliest ready time for atomic access. Writes are
184*6777b538SAndroid Build Coastguard Worker   // protected by |lock_|, but allows atomic reads outside of |lock_|. If this
185*6777b538SAndroid Build Coastguard Worker   // sequence is empty, these are in an unknown state and shouldn't be read.
186*6777b538SAndroid Build Coastguard Worker 
187*6777b538SAndroid Build Coastguard Worker   // Minimum of latest_delayed_run_time() of next delayed task if any, and
188*6777b538SAndroid Build Coastguard Worker   // |queue_time| of next immediate task if any.
GUARDED_BY(lock_)189*6777b538SAndroid Build Coastguard Worker   std::atomic<TimeTicks> latest_ready_time_ GUARDED_BY(lock_){TimeTicks()};
190*6777b538SAndroid Build Coastguard Worker   // is_null() if there is an immediate task, or earliest_delayed_run_time() of
191*6777b538SAndroid Build Coastguard Worker   // next delayed task otherwise.
GUARDED_BY(lock_)192*6777b538SAndroid Build Coastguard Worker   std::atomic<TimeTicks> earliest_ready_time_ GUARDED_BY(lock_){TimeTicks()};
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker   // True if a worker is currently associated with a Task from this Sequence.
195*6777b538SAndroid Build Coastguard Worker   bool has_worker_ = false;
196*6777b538SAndroid Build Coastguard Worker 
197*6777b538SAndroid Build Coastguard Worker   // True if the sequence has ready tasks and requested to be queued as such
198*6777b538SAndroid Build Coastguard Worker   // through WillPushImmediateTask() or OnBecomeReady(). Reset to false once all
199*6777b538SAndroid Build Coastguard Worker   // ready tasks are done being processed and either DidProcessTask() or
200*6777b538SAndroid Build Coastguard Worker   // WillReEnqueue() returned false. Normally, |is_immediate_| is protected by
201*6777b538SAndroid Build Coastguard Worker   // |lock_|, except in OnBecomeReady() hence the use of atomics.
202*6777b538SAndroid Build Coastguard Worker   std::atomic_bool is_immediate_{false};
203*6777b538SAndroid Build Coastguard Worker 
204*6777b538SAndroid Build Coastguard Worker   // Holds data stored through the SequenceLocalStorageSlot API.
205*6777b538SAndroid Build Coastguard Worker   SequenceLocalStorageMap sequence_local_storage_;
206*6777b538SAndroid Build Coastguard Worker };
207*6777b538SAndroid Build Coastguard Worker 
208*6777b538SAndroid Build Coastguard Worker }  // namespace internal
209*6777b538SAndroid Build Coastguard Worker }  // namespace base
210*6777b538SAndroid Build Coastguard Worker 
211*6777b538SAndroid Build Coastguard Worker #endif  // BASE_TASK_THREAD_POOL_SEQUENCE_H_
212