1 // Copyright 2017 The Chromium Authors. All rights reserved.
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 <vector>
9 
10 #include "base/atomicops.h"
11 #include "base/callback.h"
12 #include "base/compiler_specific.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/task/common/checked_lock.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 defined(OS_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   /* ThreadPool() as a trait is deprecated and implicit here */        \
99   static_assert(!traits.use_thread_pool(), "");                        \
100   ALLOW_UNUSED_TYPE constexpr base::TaskTraits                         \
101       LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyTraitsAreConstexpr, \
102                                             __LINE__) = traits
103 
104 // |traits| are TaskTraits used when creating the SingleThreadTaskRunner.
105 // |thread_mode| specifies whether the SingleThreadTaskRunner can share its
106 // thread with other SingleThreadTaskRunners.
107 #define LAZY_THREAD_POOL_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(traits,      \
108                                                                thread_mode) \
109   base::LazyThreadPoolSingleThreadTaskRunner::CreateInternal(traits,        \
110                                                              thread_mode);  \
111   /* ThreadPool() as a trait is deprecated and implicit here */             \
112   static_assert(!traits.use_thread_pool(), "");                             \
113   ALLOW_UNUSED_TYPE constexpr base::TaskTraits                              \
114       LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyTraitsAreConstexpr,      \
115                                             __LINE__) = traits;             \
116   ALLOW_UNUSED_TYPE constexpr base::SingleThreadTaskRunnerThreadMode        \
117       LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyThreadModeIsConstexpr,   \
118                                             __LINE__) = thread_mode
119 
120 // |traits| are TaskTraits used when creating the COM STA
121 // SingleThreadTaskRunner. |thread_mode| specifies whether the COM STA
122 // SingleThreadTaskRunner can share its thread with other
123 // SingleThreadTaskRunners.
124 #define LAZY_COM_STA_TASK_RUNNER_INITIALIZER(traits, thread_mode)            \
125   base::LazyThreadPoolCOMSTATaskRunner::CreateInternal(traits, thread_mode); \
126   /* ThreadPool() as a trait is deprecated and implicit here */              \
127   static_assert(!traits.use_thread_pool(), "");                              \
128   ALLOW_UNUSED_TYPE constexpr base::TaskTraits                               \
129       LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyTraitsAreConstexpr,       \
130                                             __LINE__) = traits;              \
131   ALLOW_UNUSED_TYPE constexpr base::SingleThreadTaskRunnerThreadMode         \
132       LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyThreadModeIsConstexpr,    \
133                                             __LINE__) = thread_mode
134 
135 namespace internal {
136 
137 template <typename TaskRunnerType, bool com_sta>
138 class BASE_EXPORT LazyThreadPoolTaskRunner {
139  public:
140   // Use the macros above rather than a direct call to this.
141   //
142   // |traits| are TaskTraits to use to create the TaskRunner. If this
143   // LazyThreadPoolTaskRunner is specialized to create a SingleThreadTaskRunner,
144   // |thread_mode| specifies whether the SingleThreadTaskRunner can share its
145   // thread with other SingleThreadTaskRunner. Otherwise, it is unused.
146   static constexpr LazyThreadPoolTaskRunner CreateInternal(
147       const TaskTraits& traits,
148       SingleThreadTaskRunnerThreadMode thread_mode =
149           SingleThreadTaskRunnerThreadMode::SHARED) {
150     return LazyThreadPoolTaskRunner(traits, thread_mode);
151   }
152 
153   // Returns the TaskRunner held by this instance. Creates it if it didn't
154   // already exist. Thread-safe.
155   scoped_refptr<TaskRunnerType> Get();
156 
157  private:
158   constexpr LazyThreadPoolTaskRunner(
159       const TaskTraits& traits,
160       SingleThreadTaskRunnerThreadMode thread_mode =
161           SingleThreadTaskRunnerThreadMode::SHARED)
traits_(traits)162       : traits_(traits), thread_mode_(thread_mode) {}
163 
164   // Releases the TaskRunner held by this instance.
165   void Reset();
166 
167   // Creates and returns a new TaskRunner.
168   scoped_refptr<TaskRunnerType> Create();
169 
170   // Creates a new TaskRunner via Create(), adds an explicit ref to it, and
171   // returns it raw. Used as an adapter for lazy instance helpers. Static and
172   // takes |this| as an explicit param to match the void* signature of
173   // GetOrCreateLazyPointer().
174   static TaskRunnerType* CreateRaw(void* void_self);
175 
176   // TaskTraits to create the TaskRunner.
177   const TaskTraits traits_;
178 
179   // SingleThreadTaskRunnerThreadMode to create the TaskRunner.
180   const SingleThreadTaskRunnerThreadMode thread_mode_;
181 
182   // Can have 3 states:
183   // - This instance does not hold a TaskRunner: 0
184   // - This instance is creating a TaskRunner: kLazyInstanceStateCreating
185   // - This instance holds a TaskRunner: Pointer to the TaskRunner.
186   // LazyInstance's internals are reused to handle transition between states.
187   subtle::AtomicWord state_ = 0;
188 
189   // No DISALLOW_COPY_AND_ASSIGN since that prevents static initialization with
190   // Visual Studio (warning C4592: 'symbol will be dynamically initialized
191   // (implementation limitation))'.
192 };
193 
194 // When a LazyThreadPoolTaskRunner becomes active (invokes Get()), it adds a
195 // callback to the current ScopedLazyTaskRunnerListForTesting, if any.
196 // Callbacks run when the ScopedLazyTaskRunnerListForTesting is
197 // destroyed. In a test process, a ScopedLazyTaskRunnerListForTesting
198 // must be instantiated before any LazyThreadPoolTaskRunner becomes active.
199 class BASE_EXPORT ScopedLazyTaskRunnerListForTesting {
200  public:
201   ScopedLazyTaskRunnerListForTesting();
202   ~ScopedLazyTaskRunnerListForTesting();
203 
204  private:
205   friend class LazyThreadPoolTaskRunner<SequencedTaskRunner, false>;
206   friend class LazyThreadPoolTaskRunner<SingleThreadTaskRunner, false>;
207 
208 #if defined(OS_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   DISALLOW_COPY_AND_ASSIGN(ScopedLazyTaskRunnerListForTesting);
221 };
222 
223 }  // namespace internal
224 }  // namespace base
225 
226 #endif  // BASE_TASK_LAZY_THREAD_POOL_TASK_RUNNER_H_
227