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