blob: 371cfb28f42199425c8d8b78c86014f6e11a4f5b [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2019 The Chromium Authors
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:382// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Gabriel Charette52fa3ae2019-04-15 21:44:375#ifndef BASE_TASK_THREAD_POOL_TASK_SOURCE_H_
6#define BASE_TASK_THREAD_POOL_TASK_SOURCE_H_
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:387
8#include <stddef.h>
9
10#include "base/base_export.h"
Patrick Monette8a0eaaa2021-10-01 20:53:0011#include "base/containers/intrusive_heap.h"
David Sandersfc1f17fa2022-04-15 00:15:4912#include "base/dcheck_is_on.h"
Keishi Hattori0e45c022021-11-27 09:25:5213#include "base/memory/raw_ptr.h"
Keishi Hattori8a7e15d2023-01-19 07:16:2914#include "base/memory/raw_ptr_exclusion.h"
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:3815#include "base/memory/ref_counted.h"
Etienne Pierre-doray312462152019-03-19 16:10:1716#include "base/sequence_token.h"
Gabriel Charetted35648382019-04-30 21:10:5917#include "base/task/common/checked_lock.h"
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:3818#include "base/task/task_traits.h"
Gabriel Charette52fa3ae2019-04-15 21:44:3719#include "base/task/thread_pool/task.h"
Etienne Pierre-dorayeed66832020-09-02 01:47:1120#include "base/task/thread_pool/task_source_sort_key.h"
Etienne Pierre-doray312462152019-03-19 16:10:1721#include "base/threading/sequence_local_storage_map.h"
Abdias Dagbekpof0a619d2022-08-10 02:06:2022#include "base/time/time.h"
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:3823
24namespace base {
25namespace internal {
26
Etienne Pierre-dorayf7f59c32019-05-24 16:50:5327class TaskTracker;
28
Etienne Pierre-doray45fd5d52019-03-28 15:19:5529enum class TaskSourceExecutionMode {
30 kParallel,
31 kSequenced,
32 kSingleThread,
Etienne Pierre-doray36afadeb2019-07-12 21:19:4133 kJob,
34 kMax = kJob,
Etienne Pierre-doray45fd5d52019-03-28 15:19:5535};
36
Etienne Pierre-doray312462152019-03-19 16:10:1737struct BASE_EXPORT ExecutionEnvironment {
38 SequenceToken token;
Keishi Hattorie175ac52022-06-07 06:24:5739 raw_ptr<SequenceLocalStorageMap> sequence_local_storage;
Etienne Pierre-doray312462152019-03-19 16:10:1740};
41
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:3842// A TaskSource is a virtual class that provides a series of Tasks that must be
Etienne Pierre-doray72ed28cb2022-12-01 01:20:1643// executed immediately or in the future.
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:3844//
Etienne Pierre-doray72ed28cb2022-12-01 01:20:1645// When a task source has delayed tasks but no immediate tasks, the scheduler
46// must call OnBecomeReady() after HasReadyTasks(now) == true, which is
47// guaranteed once now >= GetDelayedSortKey().
48//
49// A task source is registered when it's ready to be added to the immediate
50// queue. A task source is ready to be queued when either:
Etienne Pierre-dorayedbacbf2019-08-23 01:56:0551// 1- It has new tasks that can run concurrently as a result of external
Etienne Pierre-doray72ed28cb2022-12-01 01:20:1652// operations, e.g. posting a new immediate task to an empty Sequence or
53// increasing max concurrency of a JobTaskSource;
Abdias Dagbekpof0a619d2022-08-10 02:06:2054// 2- A worker finished running a task from it and both DidProcessTask() and
55// WillReEnqueue() returned true; or
Etienne Pierre-dorayedbacbf2019-08-23 01:56:0556// 3- A worker is about to run a task from it and WillRunTask() returned
57// kAllowedNotSaturated.
Etienne Pierre-doray72ed28cb2022-12-01 01:20:1658// 4- A delayed task became ready and OnBecomeReady() returns true.
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:3859//
Etienne Pierre-dorayedbacbf2019-08-23 01:56:0560// A worker may perform the following sequence of operations on a
61// RegisteredTaskSource after obtaining it from the queue:
62// 1- Check whether a task can run with WillRunTask() (and register/enqueue the
63// task source again if not saturated).
Etienne Pierre-doray388014e2019-09-13 18:40:5264// 2- (optional) Iff (1) determined that a task can run, access the next task
65// with TakeTask().
66// 3- (optional) Execute the task.
Etienne Pierre-dorayedbacbf2019-08-23 01:56:0567// 4- Inform the task source that a task was processed with DidProcessTask(),
Abdias Dagbekpof0a619d2022-08-10 02:06:2068// and re-enqueue the task source iff requested. The task source is ready to
69// run immediately iff WillReEnqueue() returns true.
Etienne Pierre-dorayedbacbf2019-08-23 01:56:0570// When a task source is registered multiple times, many overlapping chains of
71// operations may run concurrently, as permitted by WillRunTask(). This allows
72// tasks from the same task source to run in parallel.
73// However, the following invariants are kept:
74// - The number of workers concurrently running tasks never goes over the
75// intended concurrency.
76// - If the task source has more tasks that can run concurrently, it must be
77// queued.
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:3878//
Etienne Pierre-dorayedbacbf2019-08-23 01:56:0579// Note: there is a known refcounted-ownership cycle in the ThreadPool
Etienne Pierre-doray36afadeb2019-07-12 21:19:4180// architecture: TaskSource -> TaskRunner -> TaskSource -> ... This is okay so
81// long as the other owners of TaskSource (PriorityQueue and WorkerThread in
82// alternation and ThreadGroupImpl::WorkerThreadDelegateImpl::GetWork()
83// temporarily) keep running it (and taking Tasks from it as a result). A
84// dangling reference cycle would only occur should they release their reference
85// to it while it's not empty. In other words, it is only correct for them to
86// release it when DidProcessTask() returns false.
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:3887//
88// This class is thread-safe.
89class BASE_EXPORT TaskSource : public RefCountedThreadSafe<TaskSource> {
90 public:
Etienne Pierre-dorayedbacbf2019-08-23 01:56:0591 // Indicates whether WillRunTask() allows TakeTask() to be called on a
92 // RegisteredTaskSource.
93 enum class RunStatus {
94 // TakeTask() cannot be called.
95 kDisallowed,
Etienne Pierre-doray388014e2019-09-13 18:40:5296 // TakeTask() may called, and the TaskSource has not reached its maximum
Etienne Pierre-dorayedbacbf2019-08-23 01:56:0597 // concurrency (i.e. the TaskSource still needs to be queued).
98 kAllowedNotSaturated,
Etienne Pierre-doray388014e2019-09-13 18:40:5299 // TakeTask() may called, and the TaskSource has reached its maximum
Etienne Pierre-dorayedbacbf2019-08-23 01:56:05100 // concurrency (i.e. the TaskSource no longer needs to be queued).
101 kAllowedSaturated,
Etienne Pierre-doraya57964d2019-07-08 22:04:55102 };
103
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:38104 // A Transaction can perform multiple operations atomically on a
105 // TaskSource. While a Transaction is alive, it is guaranteed that nothing
106 // else will access the TaskSource; the TaskSource's lock is held for the
Etienne Pierre-doray5c37231a2023-02-22 03:41:37107 // lifetime of the Transaction. No Transaction must be held when ~TaskSource()
108 // is called.
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:38109 class BASE_EXPORT Transaction {
110 public:
111 Transaction(Transaction&& other);
David Bienvenu85cf749b2020-10-30 15:10:59112 Transaction(const Transaction&) = delete;
113 Transaction& operator=(const Transaction&) = delete;
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:38114 ~Transaction();
115
Etienne Pierre-doraya57964d2019-07-08 22:04:55116 operator bool() const { return !!task_source_; }
117
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:38118 // Sets TaskSource priority to |priority|.
119 void UpdatePriority(TaskPriority priority);
120
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:38121 // Returns the traits of all Tasks in the TaskSource.
122 TaskTraits traits() const { return task_source_->traits_; }
123
124 TaskSource* task_source() const { return task_source_; }
125
Etienne Pierre-doray5c37231a2023-02-22 03:41:37126 void Release();
127
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:38128 protected:
129 explicit Transaction(TaskSource* task_source);
130
131 private:
132 friend class TaskSource;
133
Keishi Hattori8a7e15d2023-01-19 07:16:29134 // This field is not a raw_ptr<> because it was filtered by the rewriter
135 // for: #union
136 RAW_PTR_EXCLUSION TaskSource* task_source_;
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:38137 };
138
139 // |traits| is metadata that applies to all Tasks in the TaskSource.
Etienne Pierre-doray45fd5d52019-03-28 15:19:55140 // |task_runner| is a reference to the TaskRunner feeding this TaskSource.
141 // |task_runner| can be nullptr only for tasks with no TaskRunner, in which
142 // case |execution_mode| must be kParallel. Otherwise, |execution_mode| is the
143 // execution mode of |task_runner|.
144 TaskSource(const TaskTraits& traits,
145 TaskRunner* task_runner,
146 TaskSourceExecutionMode execution_mode);
David Bienvenu85cf749b2020-10-30 15:10:59147 TaskSource(const TaskSource&) = delete;
148 TaskSource& operator=(const TaskSource&) = delete;
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:38149
150 // Begins a Transaction. This method cannot be called on a thread which has an
151 // active TaskSource::Transaction.
Daniel Cheng4455c9842022-01-13 23:26:37152 [[nodiscard]] Transaction BeginTransaction();
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:38153
Etienne Pierre-doray312462152019-03-19 16:10:17154 virtual ExecutionEnvironment GetExecutionEnvironment() = 0;
155
Etienne Pierre-doray36afadeb2019-07-12 21:19:41156 // Thread-safe but the returned value may immediately be obsolete. As such
157 // this should only be used as a best-effort guess of how many more workers
Etienne Pierre-doray3bca4922019-08-13 20:56:56158 // are needed. This may be called on an empty task source.
Etienne Pierre-doray36afadeb2019-07-12 21:19:41159 virtual size_t GetRemainingConcurrency() const = 0;
Etienne Pierre-doraya57964d2019-07-08 22:04:55160
Etienne Pierre-doray1f51cc032020-09-15 17:40:48161 // Returns a TaskSourceSortKey representing the priority of the TaskSource.
Etienne Pierre-dorayc64a8312022-08-25 22:02:35162 virtual TaskSourceSortKey GetSortKey() const = 0;
Abdias Dagbekpod9328742022-08-10 20:31:57163 // Returns a Timeticks object representing the next delayed runtime of the
164 // TaskSource.
165 virtual TimeTicks GetDelayedSortKey() const = 0;
Etienne Pierre-doray72ed28cb2022-12-01 01:20:16166 // Returns true if there are tasks ready to be executed. Thread-safe but the
167 // returned value may immediately be obsolete.
168 virtual bool HasReadyTasks(TimeTicks now) const = 0;
169 // Returns true if the TaskSource should be moved to the immediate queue
170 // due to ready delayed tasks. Note: Returns false if the TaskSource contains
171 // ready delayed tasks, but expects to already be in the immediate queue.
172 virtual bool OnBecomeReady() = 0;
Etienne Pierre-doray1f51cc032020-09-15 17:40:48173
Abdias Dagbekpo91eec582022-08-22 20:45:52174 // Support for IntrusiveHeap in ThreadGroup::PriorityQueue.
175 void SetImmediateHeapHandle(const HeapHandle& handle);
176 void ClearImmediateHeapHandle();
177 HeapHandle GetImmediateHeapHandle() const {
178 return immediate_pq_heap_handle_;
179 }
Chris Hamilton9c9ce502019-08-22 20:53:18180
Abdias Dagbekpo91eec582022-08-22 20:45:52181 HeapHandle immediate_heap_handle() const { return immediate_pq_heap_handle_; }
182
183 // Support for IntrusiveHeap in ThreadGroup::DelayedPriorityQueue.
184 void SetDelayedHeapHandle(const HeapHandle& handle);
185 void ClearDelayedHeapHandle();
186 HeapHandle GetDelayedHeapHandle() const { return delayed_pq_heap_handle_; }
187
188 HeapHandle delayed_heap_handle() const { return delayed_pq_heap_handle_; }
Etienne Pierre-dorayb38e0fd2019-03-18 19:35:38189
190 // Returns the shutdown behavior of all Tasks in the TaskSource. Can be
191 // accessed without a Transaction because it is never mutated.
192 TaskShutdownBehavior shutdown_behavior() const {