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