xref: /aosp_15_r20/external/cronet/base/task/sequenced_task_runner.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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