xref: /aosp_15_r20/external/cronet/base/task/lazy_thread_pool_task_runner.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 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_LAZY_THREAD_POOL_TASK_RUNNER_H_
6 #define BASE_TASK_LAZY_THREAD_POOL_TASK_RUNNER_H_
7 
8 #include <atomic>
9 #include <vector>
10 
11 #include "base/base_export.h"
12 #include "base/functional/callback.h"
13 #include "base/macros/uniquify.h"
14 #include "base/task/common/checked_lock.h"
15 #include "base/task/sequenced_task_runner.h"
16 #include "base/task/single_thread_task_runner.h"
17 #include "base/task/single_thread_task_runner_thread_mode.h"
18 #include "base/task/task_traits.h"
19 #include "base/thread_annotations.h"
20 #include "build/build_config.h"
21 
22 // Lazy(Sequenced|SingleThread|COMSTA)TaskRunner lazily creates a TaskRunner.
23 //
24 // Lazy(Sequenced|SingleThread|COMSTA)TaskRunner is meant to be instantiated in
25 // an anonymous namespace (no static initializer is generated) and used to post
26 // tasks to the same thread-pool-bound sequence/thread from pieces of code that
27 // don't have a better way of sharing a TaskRunner. It is important to use this
28 // class instead of a self-managed global variable or LazyInstance so that the
29 // TaskRunners do not outlive the scope of the TaskEnvironment in unit tests
30 // (otherwise the next test in the same process will die in use-after-frees).
31 //
32 // IMPORTANT: Only use this API as a last resort. Prefer storing a
33 // (Sequenced|SingleThread)TaskRunner returned by
34 // base::ThreadPool::Create(Sequenced|SingleThread|COMSTA)TaskRunner() as a
35 // member on an object accessible by all PostTask() call sites.
36 //
37 // Example usage 1:
38 //
39 // namespace {
40 // base::LazyThreadPoolSequencedTaskRunner g_sequenced_task_runner =
41 //     LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
42 //         base::TaskTraits(base::MayBlock(),
43 //                          base::TaskPriority::USER_VISIBLE));
44 // }  // namespace
45 //
46 // void SequencedFunction() {
47 //   // Different invocations of this function post to the same
48 //   // MayBlock() SequencedTaskRunner.
49 //   g_sequenced_task_runner.Get()->PostTask(FROM_HERE, base::BindOnce(...));
50 // }
51 //
52 // Example usage 2:
53 //
54 // namespace {
55 // base::LazyThreadPoolSequencedTaskRunner g_sequenced_task_task_runner =
56 //     LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
57 //         base::TaskTraits(base::MayBlock()));
58 // }  // namespace
59 //
60 // // Code from different files can access the SequencedTaskRunner via this
61 // // function.
62 // scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() {
63 //   return g_sequenced_task_runner.Get();
64 // }
65 
66 namespace base {
67 
68 namespace internal {
69 template <typename TaskRunnerType, bool com_sta>
70 class BASE_EXPORT LazyThreadPoolTaskRunner;
71 }  // namespace internal
72 
73 // Lazy SequencedTaskRunner.
74 using LazyThreadPoolSequencedTaskRunner =
75     internal::LazyThreadPoolTaskRunner<SequencedTaskRunner, false>;
76 
77 // Lazy SingleThreadTaskRunner.
78 using LazyThreadPoolSingleThreadTaskRunner =
79     internal::LazyThreadPoolTaskRunner<SingleThreadTaskRunner, false>;
80 
81 #if BUILDFLAG(IS_WIN)
82 // Lazy COM-STA enabled SingleThreadTaskRunner.
83 using LazyThreadPoolCOMSTATaskRunner =
84     internal::LazyThreadPoolTaskRunner<SingleThreadTaskRunner, true>;
85 #endif
86 
87 // Use the macros below to initialize a LazyThreadPoolTaskRunner. These macros
88 // verify that their arguments are constexpr, which is important to prevent the
89 // generation of a static initializer.
90 
91 // |traits| are TaskTraits used when creating the SequencedTaskRunner.
92 #define LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(traits) \
93   base::LazyThreadPoolSequencedTaskRunner::CreateInternal(traits); \
94   [[maybe_unused]] constexpr base::TaskTraits BASE_UNIQUIFY(       \
95       kVerifyTraitsAreConstexpr) = traits
96 
97 // |traits| are TaskTraits used when creating the SingleThreadTaskRunner.
98 // |thread_mode| specifies whether the SingleThreadTaskRunner can share its
99 // thread with other SingleThreadTaskRunners.
100 #define LAZY_THREAD_POOL_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(traits,      \
101                                                                thread_mode) \
102   base::LazyThreadPoolSingleThreadTaskRunner::CreateInternal(traits,        \
103                                                              thread_mode);  \
104   [[maybe_unused]] constexpr base::TaskTraits BASE_UNIQUIFY(                \
105       kVerifyTraitsAreConstexpr) = traits;                                  \
106   [[maybe_unused]] constexpr base::SingleThreadTaskRunnerThreadMode         \
107   BASE_UNIQUIFY(kVerifyThreadModeIsConstexpr) = thread_mode
108 
109 // |traits| are TaskTraits used when creating the COM STA
110 // SingleThreadTaskRunner. |thread_mode| specifies whether the COM STA
111 // SingleThreadTaskRunner can share its thread with other
112 // SingleThreadTaskRunners.
113 #define LAZY_COM_STA_TASK_RUNNER_INITIALIZER(traits, thread_mode)            \
114   base::LazyThreadPoolCOMSTATaskRunner::CreateInternal(traits, thread_mode); \
115   [[maybe_unused]] constexpr base::TaskTraits BASE_UNIQUIFY(                 \
116       kVerifyTraitsAreConstexpr) = traits;                                   \
117   [[maybe_unused]] constexpr base::SingleThreadTaskRunnerThreadMode          \
118   BASE_UNIQUIFY(kVerifyThreadModeIsConstexpr) = thread_mode
119 
120 namespace internal {
121 
122 template <typename TaskRunnerType, bool com_sta>
123 class BASE_EXPORT LazyThreadPoolTaskRunner {
124  public:
125   // Use the macros above rather than a direct call to this.
126   //
127   // |traits| are TaskTraits to use to create the TaskRunner. If this
128   // LazyThreadPoolTaskRunner is specialized to create a SingleThreadTaskRunner,
129   // |thread_mode| specifies whether the SingleThreadTaskRunner can share its
130   // thread with other SingleThreadTaskRunner. Otherwise, it is unused.
131   static constexpr LazyThreadPoolTaskRunner CreateInternal(
132       const TaskTraits& traits,
133       SingleThreadTaskRunnerThreadMode thread_mode =
134           SingleThreadTaskRunnerThreadMode::SHARED) {
135     return LazyThreadPoolTaskRunner(traits, thread_mode);
136   }
137 
138   // Returns the TaskRunner held by this instance. Creates it if it didn't
139   // already exist. Thread-safe.
140   scoped_refptr<TaskRunnerType> Get();
141 
142  private:
143   constexpr LazyThreadPoolTaskRunner(
144       const TaskTraits& traits,
145       SingleThreadTaskRunnerThreadMode thread_mode =
146           SingleThreadTaskRunnerThreadMode::SHARED)
traits_(traits)147       : traits_(traits), thread_mode_(thread_mode) {}
148 
149   // Releases the TaskRunner held by this instance.
150   void Reset();
151 
152   // Creates and returns a new TaskRunner.
153   scoped_refptr<TaskRunnerType> Create();
154 
155   // Creates a new TaskRunner via Create(), adds an explicit ref to it, and
156   // returns it raw. Used as an adapter for lazy instance helpers. Static and
157   // takes |this| as an explicit param to match the void* signature of
158   // GetOrCreateLazyPointer().
159   static TaskRunnerType* CreateRaw(void* void_self);
160 
161   // TaskTraits to create the TaskRunner.
162   const TaskTraits traits_;
163 
164   // SingleThreadTaskRunnerThreadMode to create the TaskRunner.
165   const SingleThreadTaskRunnerThreadMode thread_mode_;
166 
167   // Can have 3 states:
168   // - This instance does not hold a TaskRunner: 0
169   // - This instance is creating a TaskRunner: kLazyInstanceStateCreating
170   // - This instance holds a TaskRunner: Pointer to the TaskRunner.
171   // LazyInstance's internals are reused to handle transition between states.
172   std::atomic<uintptr_t> state_ = 0;
173 
174   // No DISALLOW_COPY_AND_ASSIGN since that prevents static initialization with
175   // Visual Studio (warning C4592: 'symbol will be dynamically initialized
176   // (implementation limitation))'.
177 };
178 
179 // When a LazyThreadPoolTaskRunner becomes active (invokes Get()), it adds a
180 // callback to the current ScopedLazyTaskRunnerListForTesting, if any.
181 // Callbacks run when the ScopedLazyTaskRunnerListForTesting is
182 // destroyed. In a test process, a ScopedLazyTaskRunnerListForTesting
183 // must be instantiated before any LazyThreadPoolTaskRunner becomes active.
184 class BASE_EXPORT ScopedLazyTaskRunnerListForTesting {
185  public:
186   ScopedLazyTaskRunnerListForTesting();
187 
188   ScopedLazyTaskRunnerListForTesting(
189       const ScopedLazyTaskRunnerListForTesting&) = delete;
190   ScopedLazyTaskRunnerListForTesting& operator=(
191       const ScopedLazyTaskRunnerListForTesting&) = delete;
192 
193   ~ScopedLazyTaskRunnerListForTesting();
194 
195  private:
196   friend class LazyThreadPoolTaskRunner<SequencedTaskRunner, false>;
197   friend class LazyThreadPoolTaskRunner<SingleThreadTaskRunner, false>;
198 
199 #if BUILDFLAG(IS_WIN)
200   friend class LazyThreadPoolTaskRunner<SingleThreadTaskRunner, true>;
201 #endif
202 
203   // Add |callback| to the list of callbacks to run on destruction.
204   void AddCallback(OnceClosure callback);
205 
206   CheckedLock lock_;
207 
208   // List of callbacks to run on destruction.
209   std::vector<OnceClosure> callbacks_ GUARDED_BY(lock_);
210 };
211 
212 }  // namespace internal
213 }  // namespace base
214 
215 #endif  // BASE_TASK_LAZY_THREAD_POOL_TASK_RUNNER_H_
216