xref: /aosp_15_r20/external/cronet/base/task/single_thread_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_SINGLE_THREAD_TASK_RUNNER_H_
6 #define BASE_TASK_SINGLE_THREAD_TASK_RUNNER_H_
7 
8 #include <optional>
9 
10 #include "base/auto_reset.h"
11 #include "base/base_export.h"
12 #include "base/dcheck_is_on.h"
13 #include "base/gtest_prod_util.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/task/sequenced_task_runner.h"
16 
17 namespace blink::scheduler {
18 class MainThreadSchedulerImpl;
19 }  // namespace blink::scheduler
20 
21 namespace base::sequence_manager::internal {
22 class CurrentDefaultHandleOverrideForRunOrPostTask;
23 }
24 
25 namespace base {
26 
27 class ScopedDisallowRunningRunLoop;
28 
29 // A SingleThreadTaskRunner is a SequencedTaskRunner with one more
30 // guarantee; namely, that all tasks are run on a single dedicated
31 // thread.  Most use cases require only a SequencedTaskRunner, unless
32 // there is a specific need to run tasks on only a single thread.
33 //
34 // SingleThreadTaskRunner implementations might:
35 //   - Post tasks to an existing thread's MessageLoop (see
36 //     MessageLoop::task_runner()).
37 //   - Create their own worker thread and MessageLoop to post tasks to.
38 //   - Add tasks to a FIFO and signal to a non-MessageLoop thread for them to
39 //     be processed. This allows TaskRunner-oriented code run on threads
40 //     running other kinds of message loop, e.g. Jingle threads.
41 class BASE_EXPORT SingleThreadTaskRunner : public SequencedTaskRunner {
42  public:
43   // Returns true if the `SingleThreadTaskRunner` runs tasks posted to it on the
44   // current thread.
45   //
46   // Identical to `RunsTaskInCurrentSequence()`, except from a `RunOrPostTask()`
47   // callback running synchronously (in that case, `BelongsToCurrentThread()`
48   // returns false and `RunsTaskInCurrentSequence()` returns true).
49   virtual bool BelongsToCurrentThread() const;
50 
51   // Returns the default SingleThreadTaskRunner for the current thread.
52   // On threads that service multiple task queues, the default task queue is
53   // preferred to inheriting the current task queue (otherwise, everything would
54   // implicitly be "input priority"...). If the caller knows which task queue it
55   // should be running on, it should post to that SingleThreadTaskRunner
56   // directly instead of GetCurrentDefault(). This is critical in some
57   // cases, e.g. DeleteSoon or RefCountedDeleteOnSequence should delete the
58   // object on the same task queue it's used from (or on a lower priority).
59   //
60   // DCHECKs if the current thread isn't servicing a SingleThreadTaskRunner.
61   //
62   // See
63   // https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md#Posting-to-the-Current-Virtual_Thread
64   // for details
65 
66   [[nodiscard]] static const scoped_refptr<SingleThreadTaskRunner>&
67   GetCurrentDefault();
68 
69   // Returns true if the SingleThreadTaskRunner is already created for
70   // the current thread.
71   [[nodiscard]] static bool HasCurrentDefault();
72 
73   class CurrentHandleOverrideForTesting;
74 
75   class BASE_EXPORT CurrentDefaultHandle {
76    public:
77     // Sets the value returned by `SingleThreadTaskRunner::GetCurrentDefault()`
78     // and `SequencedTaskRunner::GetCurrentDefault()` to `task_runner` within
79     // its scope. `task_runner` must belong to the current thread. There must
80     // not already be a current default `SingleThreadTaskRunner` on this thread.
81     explicit CurrentDefaultHandle(
82         scoped_refptr<SingleThreadTaskRunner> task_runner);
83 
84     CurrentDefaultHandle(const CurrentDefaultHandle&) = delete;
85     CurrentDefaultHandle& operator=(const CurrentDefaultHandle&) = delete;
86 
87     ~CurrentDefaultHandle();
88 
89    private:
90     friend class SingleThreadTaskRunner;
91 
92     // Overriding an existing current default SingleThreadTaskRunner should only
93     // be needed under special circumstances. Require them to be enumerated as
94     // friends to require //base/OWNERS review. Use
95     // SingleThreadTaskRunner::CurrentHandleOverrideForTesting in unit tests to
96     // avoid the friend requirement.
97     friend class blink::scheduler::MainThreadSchedulerImpl;
98     friend class CurrentHandleOverrideForTesting;
99     friend class sequence_manager::internal::
100         CurrentDefaultHandleOverrideForRunOrPostTask;
101     FRIEND_TEST_ALL_PREFIXES(SingleThreadTaskRunnerCurrentDefaultHandleTest,
102                              NestedRunLoopAllowedUnderHandleOverride);
103     FRIEND_TEST_ALL_PREFIXES(SingleThreadTaskRunnerCurrentDefaultHandleTest,
104                              NestedOverrideWithMayAlreadyExist);
105     FRIEND_TEST_ALL_PREFIXES(SingleThreadTaskRunnerCurrentDefaultHandleTest,
106                              OverrideWithNull);
107     FRIEND_TEST_ALL_PREFIXES(SingleThreadTaskRunnerCurrentDefaultHandleTest,
108                              OverrideWithNonNull);
109 
110     struct MayAlreadyExist {};
111 
112     // Same as the public constructor, but there may already be a current
113     // default `SingleThreadTaskRunner` on this thread.
114     CurrentDefaultHandle(scoped_refptr<SingleThreadTaskRunner> task_runner,
115                          MayAlreadyExist);
116 
117     scoped_refptr<SingleThreadTaskRunner> task_runner_;
118     raw_ptr<CurrentDefaultHandle> previous_handle_;
119     SequencedTaskRunner::CurrentDefaultHandle sequenced_handle_;
120   };
121 
122   // Overrides the current default `SingleThreadTaskRunner` and disables running
123   // a `RunLoop` within its scope.
124   //
125   // Note: Overriding the current default SingleThreadTaskRunner isn't generally
126   // desired but it's useful in some unit tests where multiple task runners
127   // share the main thread for simplicity and determinism. Only use this when no
128   // other constructs will work (see base/test/task_environment.h and
129   // base/test/test_mock_time_task_runner.h for preferred alternatives).
130   class BASE_EXPORT CurrentHandleOverrideForTesting {
131    public:
132     explicit CurrentHandleOverrideForTesting(
133         scoped_refptr<SingleThreadTaskRunner> overriding_task_runner);
134     ~CurrentHandleOverrideForTesting();
135 
136    private:
137     CurrentDefaultHandle current_default_handle_;
138     std::unique_ptr<ScopedDisallowRunningRunLoop> no_running_during_override_;
139   };
140 
141  protected:
142   ~SingleThreadTaskRunner() override = default;
143 };
144 
145 }  // namespace base
146 
147 #endif  // BASE_TASK_SINGLE_THREAD_TASK_RUNNER_H_
148