• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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