File: sequenced_task_runner.h

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (363 lines) | stat: -rw-r--r-- 14,121 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_TASK_SEQUENCED_TASK_RUNNER_H_
#define BASE_TASK_SEQUENCED_TASK_RUNNER_H_

#include <memory>

#include "base/auto_reset.h"
#include "base/base_export.h"
#include "base/functional/callback.h"
#include "base/task/delay_policy.h"
#include "base/task/delayed_task_handle.h"
#include "base/task/sequenced_task_runner_helpers.h"
#include "base/task/task_runner.h"
#include "base/types/pass_key.h"

namespace blink {
class LowPrecisionTimer;
class TimerBase;
class TimerBasedTickProvider;
class WebRtcTaskQueue;
}
namespace webrtc {
class ThreadWrapper;
}  // namespace webrtc
namespace media {
class AlsaPcmOutputStream;
class AlsaPcmInputStream;
class FakeAudioWorker;
}  // namespace media

namespace base {

namespace internal {
class DelayTimerBase;
class DelayedTaskManager;
}
class DeadlineTimer;
class MetronomeTimer;
class TimeDelta;
class TimeTicks;

namespace subtle {

// Used to restrict access to PostCancelableDelayedTaskAt() to authorize
// callers.
class PostDelayedTaskPassKey {
 private:
  // Avoid =default to disallow creation by uniform initialization.
  PostDelayedTaskPassKey() {}

  friend class base::internal::DelayTimerBase;
  friend class base::internal::DelayedTaskManager;
  friend class base::DeadlineTimer;
  friend class base::MetronomeTimer;
  friend class blink::LowPrecisionTimer;
  friend class blink::TimerBase;
  friend class blink::TimerBasedTickProvider;
  friend class blink::WebRtcTaskQueue;
  friend class PostDelayedTaskPassKeyForTesting;
  friend class webrtc::ThreadWrapper;
  friend class media::AlsaPcmOutputStream;
  friend class media::AlsaPcmInputStream;
  friend class media::FakeAudioWorker;
};

class PostDelayedTaskPassKeyForTesting : public PostDelayedTaskPassKey {};

}  // namespace subtle

// A SequencedTaskRunner is a subclass of TaskRunner that provides
// additional guarantees on the order that tasks are started, as well
// as guarantees on when tasks are in sequence, i.e. one task finishes
// before the other one starts.
//
// Summary
// -------
// Non-nested tasks with the same delay will run one by one in FIFO
// order.
//
// Detailed guarantees
// -------------------
//
// SequencedTaskRunner also adds additional methods for posting
// non-nestable tasks.  In general, an implementation of TaskRunner
// may expose task-running methods which are themselves callable from
// within tasks.  A non-nestable task is one that is guaranteed to not
// be run from within an already-running task.  Conversely, a nestable
// task (the default) is a task that can be run from within an
// already-running task.
//
// The guarantees of SequencedTaskRunner are as follows:
//
//   - Given two tasks T2 and T1, T2 will start after T1 starts if:
//
//       * T2 is posted after T1; and
//       * T2 has equal or higher delay than T1; and
//       * T2 is non-nestable or T1 is nestable.
//
//   - If T2 will start after T1 starts by the above guarantee, then
//     T2 will start after T1 finishes and is destroyed if:
//
//       * T2 is non-nestable, or
//       * T1 doesn't call any task-running methods.
//
//   - If T2 will start after T1 finishes by the above guarantee, then
//     all memory changes in T1 and T1's destruction will be visible
//     to T2.
//
//   - If T2 runs nested within T1 via a call to the task-running
//     method M, then all memory changes in T1 up to the call to M
//     will be visible to T2, and all memory changes in T2 will be
//     visible to T1 from the return from M.
//
// Note that SequencedTaskRunner does not guarantee that tasks are run
// on a single dedicated thread, although the above guarantees provide
// most (but not all) of the same guarantees.  If you do need to
// guarantee that tasks are run on a single dedicated thread, see
// SingleThreadTaskRunner (in single_thread_task_runner.h).
//
// Some corollaries to the above guarantees, assuming the tasks in
// question don't call any task-running methods:
//
//   - Tasks posted via PostTask are run in FIFO order.
//
//   - Tasks posted via PostNonNestableTask are run in FIFO order.
//
//   - Tasks posted with the same delay and the same nestable state
//     are run in FIFO order.
//
//   - A list of tasks with the same nestable state posted in order of
//     non-decreasing delay is run in FIFO order.
//
//   - A list of tasks posted in order of non-decreasing delay with at
//     most a single change in nestable state from nestable to
//     non-nestable is run in FIFO order. (This is equivalent to the
//     statement of the first guarantee above.)
//
// Some theoretical implementations of SequencedTaskRunner:
//
//   - A SequencedTaskRunner that wraps a regular TaskRunner but makes
//     sure that only one task at a time is posted to the TaskRunner,
//     with appropriate memory barriers in between tasks.
//
//   - A SequencedTaskRunner that, for each task, spawns a joinable
//     thread to run that task and immediately quit, and then
//     immediately joins that thread.
//
//   - A SequencedTaskRunner that stores the list of posted tasks and
//     has a method Run() that runs each runnable task in FIFO order
//     that can be called from any thread, but only if another
//     (non-nested) Run() call isn't already happening.
//
// SequencedTaskRunner::GetCurrentDefault() can be used while running
// a task to retrieve the default SequencedTaskRunner for the current
// sequence.
class BASE_EXPORT SequencedTaskRunner : public TaskRunner {
 public:
  // The two PostNonNestable*Task methods below are like their
  // nestable equivalents in TaskRunner, but they guarantee that the
  // posted task will not run nested within an already-running task.
  //
  // A simple corollary is that posting a task as non-nestable can
  // only delay when the task gets run.  That is, posting a task as
  // non-nestable may not affect when the task gets run, or it could
  // make it run later than it normally would, but it won't make it
  // run earlier than it normally would.

  // TODO(akalin): Get rid of the boolean return value for the methods
  // below.

  bool PostNonNestableTask(const Location& from_here, OnceClosure task);

  virtual bool PostNonNestableDelayedTask(const Location& from_here,
                                          OnceClosure task,
                                          base::TimeDelta delay) = 0;

  // Posts the given |task| to be run only after |delay| has passed. Returns a
  // handle that can be used to cancel the task. This should not be used
  // directly. Consider using higher level timer primitives in
  // base/timer/timer.h.
  //
  // The handle is only guaranteed valid while the task is pending execution.
  // This means that it may be invalid if the posting failed, and will be
  // invalid while the task is executing. Calling CancelTask() on an invalid
  // handle is a no-op.
  //
  // This method and the handle it returns are not thread-safe and can only be
  // used from the sequence this task runner runs its tasks on.
  virtual DelayedTaskHandle PostCancelableDelayedTask(
      subtle::PostDelayedTaskPassKey,
      const Location& from_here,
      OnceClosure task,
      TimeDelta delay);

  // Posts the given |task| to be run at |delayed_run_time| (or immediately if
  // in the past), following |delay_policy|. Returns a handle that can be used
  // to cancel the task. This should not be used directly. Consider using higher
  // level timer primitives in base/timer/timer.h.
  [[nodiscard]] virtual DelayedTaskHandle PostCancelableDelayedTaskAt(
      subtle::PostDelayedTaskPassKey,
      const Location& from_here,
      OnceClosure task,
      TimeTicks delayed_run_time,
      subtle::DelayPolicy delay_policy);

  // Posts the given |task| to be run at |delayed_run_time| (or immediately if
  // in the past), following |delay_policy|. This is used by the default
  // implementation of PostCancelableDelayedTaskAt(). The default behavior
  // subtracts TimeTicks::Now() from |delayed_run_time| to get a delay. See
  // base::Timer to post precise/repeating timeouts.
  // TODO(1153139): Make pure virtual once all SequencedTaskRunners implement
  // this.
  virtual bool PostDelayedTaskAt(subtle::PostDelayedTaskPassKey,
                                 const Location& from_here,
                                 OnceClosure task,
                                 TimeTicks delayed_run_time,
                                 subtle::DelayPolicy delay_policy);

  // Submits a non-nestable task to delete the given object.  Returns
  // true if the object may be deleted at some point in the future,
  // and false if the object definitely will not be deleted.
  //
  // By default, this leaks `object` if the deleter task doesn't run, e.g. if
  // the underlying task queue is shut down first. Subclasses can override this
  // behavior by specializing `DeleteOrReleaseSoonInternal()`.
  template <class T>
  bool DeleteSoon(const Location& from_here, const T* object) {
    return DeleteOrReleaseSoonInternal(from_here, &DeleteHelper<T>::DoDelete,
                                       object);
  }

  template <class T>
  bool DeleteSoon(const Location& from_here, std::unique_ptr<T> object) {
    return DeleteOrReleaseSoonInternal(
        from_here, &DeleteUniquePtrHelper<T>::DoDelete, object.release());
  }

  // Submits a non-nestable task to release the given object.
  //
  // By default, this leaks `object` if the releaser task doesn't run, e.g. if
  // the underlying task queue is shut down first. Subclasses can override this
  // behavior by specializing `DeleteOrReleaseSoonInternal()`.
  //
  // ReleaseSoon makes sure that the object it the scoped_refptr points to gets
  // properly released on the correct thread.
  // We apply ReleaseSoon to the rvalue as the side-effects can be unclear to
  // the caller if an lvalue is used. That being so, the scoped_refptr should
  // always be std::move'd.
  // Example use:
  //
  // scoped_refptr<T> foo_scoped_refptr;
  // ...
  // task_runner->ReleaseSoon(std::move(foo_scoped_refptr));
  template <class T>
  void ReleaseSoon(const Location& from_here, scoped_refptr<T>&& object) {
    if (!object)
      return;

    DeleteOrReleaseSoonInternal(from_here, &ReleaseHelper<T>::DoRelease,
                                object.release());
  }

  // Returns true iff tasks posted to this TaskRunner are sequenced
  // with this call.
  //
  // In particular:
  // - Returns true if this is a SequencedTaskRunner to which the
  //   current task was posted.
  // - Returns true if this is a SequencedTaskRunner bound to the
  //   same sequence as the SequencedTaskRunner to which the current
  //   task was posted.
  // - Returns true if this is a SingleThreadTaskRunner bound to
  //   the current thread.
  virtual bool RunsTasksInCurrentSequence() const = 0;

  // Returns the default SequencedTaskRunner for the current task. It
  // should only be called if HasCurrentDefault() returns true (see the comment
  // there for the requirements).
  //
  // It is "default" in the sense that if the current sequence multiplexes
  // multiple task queues (e.g. BrowserThread::UI), this will return the default
  // task queue. A caller that wants a specific task queue should obtain it
  // directly instead of going through this API.
  //
  // See
  // https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md#Posting-to-the-Current-Virtual_Thread
  // for details
  [[nodiscard]] static const scoped_refptr<SequencedTaskRunner>&
  GetCurrentDefault();

  // Returns true if one of the following conditions is fulfilled:
  // a) A SequencedTaskRunner has been assigned to the current thread by
  //    instantiating a SequencedTaskRunner::CurrentDefaultHandle.
  // b) The current thread has a SingleThreadTaskRunner::CurrentDefaultHandle
  //    (which includes any thread that runs a MessagePump).
  [[nodiscard]] static bool HasCurrentDefault();

  class BASE_EXPORT CurrentDefaultHandle {
   public:
    // Binds `task_runner` to the current thread so that it is returned by
    // GetCurrentDefault() in the scope of the constructed
    // `CurrentDefaultHandle`.
    explicit CurrentDefaultHandle(
        scoped_refptr<SequencedTaskRunner> task_runner);

    CurrentDefaultHandle(const CurrentDefaultHandle&) = delete;
    CurrentDefaultHandle& operator=(const CurrentDefaultHandle&) = delete;

    ~CurrentDefaultHandle();

   private:
    friend class SequencedTaskRunner;
    friend class CurrentHandleOverride;

    const AutoReset<CurrentDefaultHandle*> resetter_;

    scoped_refptr<SequencedTaskRunner> task_runner_;
  };

 protected:
  ~SequencedTaskRunner() override = default;

  // Helper to allow SingleThreadTaskRunner::CurrentDefaultHandle to double as a
  // SequencedTaskRunner::CurrentDefaultHandle.
  static void SetCurrentDefaultHandleTaskRunner(
      CurrentDefaultHandle& current_default,
      scoped_refptr<SequencedTaskRunner> task_runner) {
    current_default.task_runner_ = task_runner;
  }

  virtual bool DeleteOrReleaseSoonInternal(const Location& from_here,
                                           void (*deleter)(const void*),
                                           const void* object);
};

// Sample usage with std::unique_ptr :
// std::unique_ptr<Foo, base::OnTaskRunnerDeleter> ptr(
//     new Foo, base::OnTaskRunnerDeleter(my_task_runner));
//
// For RefCounted see base::RefCountedDeleteOnSequence.
struct BASE_EXPORT OnTaskRunnerDeleter {
  explicit OnTaskRunnerDeleter(scoped_refptr<SequencedTaskRunner> task_runner);
  ~OnTaskRunnerDeleter();

  OnTaskRunnerDeleter(OnTaskRunnerDeleter&&);
  OnTaskRunnerDeleter& operator=(OnTaskRunnerDeleter&&);

  // For compatibility with std:: deleters.
  template <typename T>
  void operator()(const T* ptr) {
    if (ptr)
      task_runner_->DeleteSoon(FROM_HERE, ptr);
  }

  scoped_refptr<SequencedTaskRunner> task_runner_;
};

}  // namespace base

#endif  // BASE_TASK_SEQUENCED_TASK_RUNNER_H_