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