1 // Copyright 2012 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 #ifndef BASE_TASK_SEQUENCED_TASK_RUNNER_H_ 6 #define BASE_TASK_SEQUENCED_TASK_RUNNER_H_ 7 8 #include <memory> 9 10 #include "base/auto_reset.h" 11 #include "base/base_export.h" 12 #include "base/functional/callback.h" 13 #include "base/task/delay_policy.h" 14 #include "base/task/delayed_task_handle.h" 15 #include "base/task/sequenced_task_runner_helpers.h" 16 #include "base/task/task_runner.h" 17 #include "base/types/pass_key.h" 18 19 namespace blink { 20 class LowPrecisionTimer; 21 class TimerBase; 22 class TimerBasedTickProvider; 23 class WebRtcTaskQueue; 24 } 25 namespace webrtc { 26 class ThreadWrapper; 27 } // namespace webrtc 28 namespace media { 29 class AlsaPcmOutputStream; 30 class AlsaPcmInputStream; 31 class FakeAudioWorker; 32 } // namespace media 33 34 namespace base { 35 36 namespace internal { 37 class DelayTimerBase; 38 class DelayedTaskManager; 39 } 40 class DeadlineTimer; 41 class MetronomeTimer; 42 class TimeDelta; 43 class TimeTicks; 44 45 namespace subtle { 46 47 // Used to restrict access to PostCancelableDelayedTaskAt() to authorize 48 // callers. 49 class PostDelayedTaskPassKey { 50 private: 51 // Avoid =default to disallow creation by uniform initialization. PostDelayedTaskPassKey()52 PostDelayedTaskPassKey() {} 53 54 friend class base::internal::DelayTimerBase; 55 friend class base::internal::DelayedTaskManager; 56 friend class base::DeadlineTimer; 57 friend class base::MetronomeTimer; 58 friend class blink::LowPrecisionTimer; 59 friend class blink::TimerBase; 60 friend class blink::TimerBasedTickProvider; 61 friend class blink::WebRtcTaskQueue; 62 friend class PostDelayedTaskPassKeyForTesting; 63 friend class webrtc::ThreadWrapper; 64 friend class media::AlsaPcmOutputStream; 65 friend class media::AlsaPcmInputStream; 66 friend class media::FakeAudioWorker; 67 }; 68 69 class PostDelayedTaskPassKeyForTesting : public PostDelayedTaskPassKey {}; 70 71 } // namespace subtle 72 73 // A SequencedTaskRunner is a subclass of TaskRunner that provides 74 // additional guarantees on the order that tasks are started, as well 75 // as guarantees on when tasks are in sequence, i.e. one task finishes 76 // before the other one starts. 77 // 78 // Summary 79 // ------- 80 // Non-nested tasks with the same delay will run one by one in FIFO 81 // order. 82 // 83 // Detailed guarantees 84 // ------------------- 85 // 86 // SequencedTaskRunner also adds additional methods for posting 87 // non-nestable tasks. In general, an implementation of TaskRunner 88 // may expose task-running methods which are themselves callable from 89 // within tasks. A non-nestable task is one that is guaranteed to not 90 // be run from within an already-running task. Conversely, a nestable 91 // task (the default) is a task that can be run from within an 92 // already-running task. 93 // 94 // The guarantees of SequencedTaskRunner are as follows: 95 // 96 // - Given two tasks T2 and T1, T2 will start after T1 starts if: 97 // 98 // * T2 is posted after T1; and 99 // * T2 has equal or higher delay than T1; and 100 // * T2 is non-nestable or T1 is nestable. 101 // 102 // - If T2 will start after T1 starts by the above guarantee, then 103 // T2 will start after T1 finishes and is destroyed if: 104 // 105 // * T2 is non-nestable, or 106 // * T1 doesn't call any task-running methods. 107 // 108 // - If T2 will start after T1 finishes by the above guarantee, then 109 // all memory changes in T1 and T1's destruction will be visible 110 // to T2. 111 // 112 // - If T2 runs nested within T1 via a call to the task-running 113 // method M, then all memory changes in T1 up to the call to M 114 // will be visible to T2, and all memory changes in T2 will be 115 // visible to T1 from the return from M. 116 // 117 // Note that SequencedTaskRunner does not guarantee that tasks are run 118 // on a single dedicated thread, although the above guarantees provide 119 // most (but not all) of the same guarantees. If you do need to 120 // guarantee that tasks are run on a single dedicated thread, see 121 // SingleThreadTaskRunner (in single_thread_task_runner.h). 122 // 123 // Some corollaries to the above guarantees, assuming the tasks in 124 // question don't call any task-running methods: 125 // 126 // - Tasks posted via PostTask are run in FIFO order. 127 // 128 // - Tasks posted via PostNonNestableTask are run in FIFO order. 129 // 130 // - Tasks posted with the same delay and the same nestable state 131 // are run in FIFO order. 132 // 133 // - A list of tasks with the same nestable state posted in order of 134 // non-decreasing delay is run in FIFO order. 135 // 136 // - A list of tasks posted in order of non-decreasing delay with at 137 // most a single change in nestable state from nestable to 138 // non-nestable is run in FIFO order. (This is equivalent to the 139 // statement of the first guarantee above.) 140 // 141 // Some theoretical implementations of SequencedTaskRunner: 142 // 143 // - A SequencedTaskRunner that wraps a regular TaskRunner but makes 144 // sure that only one task at a time is posted to the TaskRunner, 145 // with appropriate memory barriers in between tasks. 146 // 147 // - A SequencedTaskRunner that, for each task, spawns a joinable 148 // thread to run that task and immediately quit, and then 149 // immediately joins that thread. 150 // 151 // - A SequencedTaskRunner that stores the list of posted tasks and 152 // has a method Run() that runs each runnable task in FIFO order 153 // that can be called from any thread, but only if another 154 // (non-nested) Run() call isn't already happening. 155 // 156 // SequencedTaskRunner::GetCurrentDefault() can be used while running 157 // a task to retrieve the default SequencedTaskRunner for the current 158 // sequence. 159 class BASE_EXPORT SequencedTaskRunner : public TaskRunner { 160 public: 161 // The two PostNonNestable*Task methods below are like their 162 // nestable equivalents in TaskRunner, but they guarantee that the 163 // posted task will not run nested within an already-running task. 164 // 165 // A simple corollary is that posting a task as non-nestable can 166 // only delay when the task gets run. That is, posting a task as 167 // non-nestable may not affect when the task gets run, or it could 168 // make it run later than it normally would, but it won't make it 169 // run earlier than it normally would. 170 171 // TODO(akalin): Get rid of the boolean return value for the methods 172 // below. 173 174 bool PostNonNestableTask(const Location& from_here, OnceClosure task); 175 176 virtual bool PostNonNestableDelayedTask(const Location& from_here, 177 OnceClosure task, 178 base::TimeDelta delay) = 0; 179 180 // Posts the given |task| to be run only after |delay| has passed. Returns a 181 // handle that can be used to cancel the task. This should not be used 182 // directly. Consider using higher level timer primitives in 183 // base/timer/timer.h. 184 // 185 // The handle is only guaranteed valid while the task is pending execution. 186 // This means that it may be invalid if the posting failed, and will be 187 // invalid while the task is executing. Calling CancelTask() on an invalid 188 // handle is a no-op. 189 // 190 // This method and the handle it returns are not thread-safe and can only be 191 // used from the sequence this task runner runs its tasks on. 192 virtual DelayedTaskHandle PostCancelableDelayedTask( 193 subtle::PostDelayedTaskPassKey, 194 const Location& from_here, 195 OnceClosure task, 196 TimeDelta delay); 197 198 // Posts the given |task| to be run at |delayed_run_time| (or immediately if 199 // in the past), following |delay_policy|. Returns a handle that can be used 200 // to cancel the task. This should not be used directly. Consider using higher 201 // level timer primitives in base/timer/timer.h. 202 [[nodiscard]] virtual DelayedTaskHandle PostCancelableDelayedTaskAt( 203 subtle::PostDelayedTaskPassKey, 204 const Location& from_here, 205 OnceClosure task, 206 TimeTicks delayed_run_time, 207 subtle::DelayPolicy delay_policy); 208 209 // Posts the given |task| to be run at |delayed_run_time| (or immediately if 210 // in the past), following |delay_policy|. This is used by the default 211 // implementation of PostCancelableDelayedTaskAt(). The default behavior 212 // subtracts TimeTicks::Now() from |delayed_run_time| to get a delay. See 213 // base::Timer to post precise/repeating timeouts. 214 // TODO(1153139): Make pure virtual once all SequencedTaskRunners implement 215 // this. 216 virtual bool PostDelayedTaskAt(subtle::PostDelayedTaskPassKey, 217 const Location& from_here, 218 OnceClosure task, 219 TimeTicks delayed_run_time, 220 subtle::DelayPolicy delay_policy); 221 222 // Submits a non-nestable task to delete the given object. Returns 223 // true if the object may be deleted at some point in the future, 224 // and false if the object definitely will not be deleted. 225 // 226 // By default, this leaks `object` if the deleter task doesn't run, e.g. if 227 // the underlying task queue is shut down first. Subclasses can override this 228 // behavior by specializing `DeleteOrReleaseSoonInternal()`. 229 template <class T> DeleteSoon(const Location & from_here,const T * object)230 bool DeleteSoon(const Location& from_here, const T* object) { 231 return DeleteOrReleaseSoonInternal(from_here, &DeleteHelper<T>::DoDelete, 232 object); 233 } 234 235 template <class T> DeleteSoon(const Location & from_here,std::unique_ptr<T> object)236 bool DeleteSoon(const Location& from_here, std::unique_ptr<T> object) { 237 return DeleteOrReleaseSoonInternal( 238 from_here, &DeleteUniquePtrHelper<T>::DoDelete, object.release()); 239 } 240 241 // Submits a non-nestable task to release the given object. 242 // 243 // By default, this leaks `object` if the releaser task doesn't run, e.g. if 244 // the underlying task queue is shut down first. Subclasses can override this 245 // behavior by specializing `DeleteOrReleaseSoonInternal()`. 246 // 247 // ReleaseSoon makes sure that the object it the scoped_refptr points to gets 248 // properly released on the correct thread. 249 // We apply ReleaseSoon to the rvalue as the side-effects can be unclear to 250 // the caller if an lvalue is used. That being so, the scoped_refptr should 251 // always be std::move'd. 252 // Example use: 253 // 254 // scoped_refptr<T> foo_scoped_refptr; 255 // ... 256 // task_runner->ReleaseSoon(std::move(foo_scoped_refptr)); 257 template <class T> ReleaseSoon(const Location & from_here,scoped_refptr<T> && object)258 void ReleaseSoon(const Location& from_here, scoped_refptr<T>&& object) { 259 if (!object) 260 return; 261 262 DeleteOrReleaseSoonInternal(from_here, &ReleaseHelper<T>::DoRelease, 263 object.release()); 264 } 265 266 // Returns true iff tasks posted to this TaskRunner are sequenced 267 // with this call. 268 // 269 // In particular: 270 // - Returns true if this is a SequencedTaskRunner to which the 271 // current task was posted. 272 // - Returns true if this is a SequencedTaskRunner bound to the 273 // same sequence as the SequencedTaskRunner to which the current 274 // task was posted. 275 // - Returns true if this is a SingleThreadTaskRunner bound to 276 // the current thread. 277 virtual bool RunsTasksInCurrentSequence() const = 0; 278 279 // Returns the default SequencedThreadTaskRunner for the current task. It 280 // should only be called if HasCurrentDefault() returns true (see the comment 281 // there for the requirements). 282 // 283 // It is "default" in the sense that if the current sequence multiplexes 284 // multiple task queues (e.g. BrowserThread::UI), this will return the default 285 // task queue. A caller that wants a specific task queue should obtain it 286 // directly instead of going through this API. 287 // 288 // See 289 // https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md#Posting-to-the-Current-Virtual_Thread 290 // for details 291 [[nodiscard]] static const scoped_refptr<SequencedTaskRunner>& 292 GetCurrentDefault(); 293 294 // Returns true if one of the following conditions is fulfilled: 295 // a) A SequencedTaskRunner has been assigned to the current thread by 296 // instantiating a SequencedTaskRunner::CurrentDefaultHandle. 297 // b) The current thread has a SingleThreadTaskRunner::CurrentDefaultHandle 298 // (which includes any thread that runs a MessagePump). 299 [[nodiscard]] static bool HasCurrentDefault(); 300 301 class BASE_EXPORT CurrentDefaultHandle { 302 public: 303 // Binds `task_runner` to the current thread so that it is returned by 304 // GetCurrentDefault() in the scope of the constructed 305 // `CurrentDefaultHandle`. 306 explicit CurrentDefaultHandle( 307 scoped_refptr<SequencedTaskRunner> task_runner); 308 309 CurrentDefaultHandle(const CurrentDefaultHandle&) = delete; 310 CurrentDefaultHandle& operator=(const CurrentDefaultHandle&) = delete; 311 312 ~CurrentDefaultHandle(); 313 314 private: 315 friend class SequencedTaskRunner; 316 friend class CurrentHandleOverride; 317 318 const AutoReset<CurrentDefaultHandle*> resetter_; 319 320 scoped_refptr<SequencedTaskRunner> task_runner_; 321 }; 322 323 protected: 324 ~SequencedTaskRunner() override = default; 325 326 // Helper to allow SingleThreadTaskRunner::CurrentDefaultHandle to double as a 327 // SequencedTaskRunner::CurrentDefaultHandle. SetCurrentDefaultHandleTaskRunner(CurrentDefaultHandle & current_default,scoped_refptr<SequencedTaskRunner> task_runner)328 static void SetCurrentDefaultHandleTaskRunner( 329 CurrentDefaultHandle& current_default, 330 scoped_refptr<SequencedTaskRunner> task_runner) { 331 current_default.task_runner_ = task_runner; 332 } 333 334 virtual bool DeleteOrReleaseSoonInternal(const Location& from_here, 335 void (*deleter)(const void*), 336 const void* object); 337 }; 338 339 // Sample usage with std::unique_ptr : 340 // std::unique_ptr<Foo, base::OnTaskRunnerDeleter> ptr( 341 // new Foo, base::OnTaskRunnerDeleter(my_task_runner)); 342 // 343 // For RefCounted see base::RefCountedDeleteOnSequence. 344 struct BASE_EXPORT OnTaskRunnerDeleter { 345 explicit OnTaskRunnerDeleter(scoped_refptr<SequencedTaskRunner> task_runner); 346 ~OnTaskRunnerDeleter(); 347 348 OnTaskRunnerDeleter(OnTaskRunnerDeleter&&); 349 OnTaskRunnerDeleter& operator=(OnTaskRunnerDeleter&&); 350 351 // For compatibility with std:: deleters. 352 template <typename T> operatorOnTaskRunnerDeleter353 void operator()(const T* ptr) { 354 if (ptr) 355 task_runner_->DeleteSoon(FROM_HERE, ptr); 356 } 357 358 scoped_refptr<SequencedTaskRunner> task_runner_; 359 }; 360 361 } // namespace base 362 363 #endif // BASE_TASK_SEQUENCED_TASK_RUNNER_H_ 364