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_SCHEDULER_LAZY_TASK_RUNNER_H_
6 #define BASE_TASK_SCHEDULER_LAZY_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/lazy_instance_helpers.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/task_scheduler/scheduler_lock.h"
17 #include "base/task_scheduler/single_thread_task_runner_thread_mode.h"
18 #include "base/task_scheduler/task_traits.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 sequence/thread from pieces of code that don't have a
26 // better way of sharing a TaskRunner. It is important to use this class
27 // instead of a self-managed global variable or LazyInstance so that the
28 // TaskRunners do not outlive the scope of the ScopedTaskEnvironment in unit
29 // tests (otherwise the next test in the same process will die in use-after-
30 // frees).
31 //
32 // IMPORTANT: Only use this API as a last resort. Prefer storing a
33 // (Sequenced|SingleThread)TaskRunner returned by
34 // base::Create(Sequenced|SingleThread|COMSTA)TaskRunnerWithTraits() as a member
35 // on an object accessible by all PostTask() call sites.
36 //
37 // Example usage 1:
38 //
39 // namespace {
40 // base::LazySequencedTaskRunner g_sequenced_task_runner =
41 //     LAZY_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::LazySequencedTaskRunner g_sequenced_task_task_runner =
56 //     LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({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 LazyTaskRunner;
70 }  // namespace internal
71 
72 // Lazy SequencedTaskRunner.
73 using LazySequencedTaskRunner =
74     internal::LazyTaskRunner<SequencedTaskRunner, false>;
75 
76 // Lazy SingleThreadTaskRunner.
77 using LazySingleThreadTaskRunner =
78     internal::LazyTaskRunner<SingleThreadTaskRunner, false>;
79 
80 #if defined(OS_WIN)
81 // Lazy COM-STA enabled SingleThreadTaskRunner.
82 using LazyCOMSTATaskRunner =
83     internal::LazyTaskRunner<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 LazyTaskRunner. These macros verify that
92 // their arguments are constexpr, which is important to prevent the generation
93 // of a static initializer.
94 
95 // |traits| are TaskTraits used when creating the SequencedTaskRunner.
96 #define LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER(traits)                 \
97   base::LazySequencedTaskRunner::CreateInternal(traits);               \
98   ALLOW_UNUSED_TYPE 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_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(traits, thread_mode)   \
106   base::LazySingleThreadTaskRunner::CreateInternal(traits, thread_mode);  \
107   ALLOW_UNUSED_TYPE constexpr base::TaskTraits                            \
108       LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyTraitsAreConstexpr,    \
109                                             __LINE__) = traits;           \
110   ALLOW_UNUSED_TYPE constexpr base::SingleThreadTaskRunnerThreadMode      \
111       LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyThreadModeIsConstexpr, \
112                                             __LINE__) = thread_mode
113 
114 // |traits| are TaskTraits used when creating the COM STA
115 // SingleThreadTaskRunner. |thread_mode| specifies whether the COM STA
116 // SingleThreadTaskRunner can share its thread with other
117 // SingleThreadTaskRunners.
118 #define LAZY_COM_STA_TASK_RUNNER_INITIALIZER(traits, thread_mode)         \
119   base::LazyCOMSTATaskRunner::CreateInternal(traits, thread_mode);        \
120   ALLOW_UNUSED_TYPE constexpr base::TaskTraits                            \
121       LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyTraitsAreConstexpr,    \
122                                             __LINE__) = traits;           \
123   ALLOW_UNUSED_TYPE constexpr base::SingleThreadTaskRunnerThreadMode      \
124       LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyThreadModeIsConstexpr, \
125                                             __LINE__) = thread_mode
126 
127 namespace internal {
128 
129 template <typename TaskRunnerType, bool com_sta>
130 class BASE_EXPORT LazyTaskRunner {
131  public:
132   // Use the macros above rather than a direct call to this.
133   //
134   // |traits| are TaskTraits to use to create the TaskRunner. If this
135   // LazyTaskRunner is specialized to create a SingleThreadTaskRunner,
136   // |thread_mode| specifies whether the SingleThreadTaskRunner can share its
137   // thread with other SingleThreadTaskRunner. Otherwise, it is unused.
138   static constexpr LazyTaskRunner CreateInternal(
139       const TaskTraits& traits,
140       SingleThreadTaskRunnerThreadMode thread_mode =
141           SingleThreadTaskRunnerThreadMode::SHARED) {
142     return LazyTaskRunner(traits, thread_mode);
143   }
144 
145   // Returns the TaskRunner held by this instance. Creates it if it didn't
146   // already exist. Thread-safe.
147   scoped_refptr<TaskRunnerType> Get();
148 
149  private:
150   constexpr LazyTaskRunner(const TaskTraits& traits,
151                            SingleThreadTaskRunnerThreadMode thread_mode =
152                                SingleThreadTaskRunnerThreadMode::SHARED)
traits_(traits)153       : traits_(traits), thread_mode_(thread_mode) {}
154 
155   // Releases the TaskRunner held by this instance.
156   void Reset();
157 
158   // Creates and returns a new TaskRunner.
159   scoped_refptr<TaskRunnerType> Create();
160 
161   // Creates a new TaskRunner via Create(), adds an explicit ref to it, and
162   // returns it raw. Used as an adapter for lazy instance helpers. Static and
163   // takes |this| as an explicit param to match the void* signature of
164   // GetOrCreateLazyPointer().
165   static TaskRunnerType* CreateRaw(void* void_self);
166 
167   // TaskTraits to create the TaskRunner.
168   const TaskTraits traits_;
169 
170   // SingleThreadTaskRunnerThreadMode to create the TaskRunner.
171   const SingleThreadTaskRunnerThreadMode thread_mode_;
172 
173   // Can have 3 states:
174   // - This instance does not hold a TaskRunner: 0
175   // - This instance is creating a TaskRunner: kLazyInstanceStateCreating
176   // - This instance holds a TaskRunner: Pointer to the TaskRunner.
177   // LazyInstance's internals are reused to handle transition between states.
178   subtle::AtomicWord state_ = 0;
179 
180   // No DISALLOW_COPY_AND_ASSIGN since that prevents static initialization with
181   // Visual Studio (warning C4592: 'symbol will be dynamically initialized
182   // (implementation limitation))'.
183 };
184 
185 // When a LazyTaskRunner becomes active (invokes Get()), it adds a callback to
186 // the current ScopedLazyTaskRunnerListForTesting, if any. Callbacks run when
187 // the ScopedLazyTaskRunnerListForTesting is destroyed. In a test process, a
188 // ScopedLazyTaskRunnerListForTesting must be instantiated before any
189 // LazyTaskRunner becomes active.
190 class BASE_EXPORT ScopedLazyTaskRunnerListForTesting {
191  public:
192   ScopedLazyTaskRunnerListForTesting();
193   ~ScopedLazyTaskRunnerListForTesting();
194 
195  private:
196   friend class LazyTaskRunner<SequencedTaskRunner, false>;
197   friend class LazyTaskRunner<SingleThreadTaskRunner, false>;
198 
199 #if defined(OS_WIN)
200   friend class LazyTaskRunner<SingleThreadTaskRunner, true>;
201 #endif
202 
203   // Add |callback| to the list of callbacks to run on destruction.
204   void AddCallback(OnceClosure callback);
205 
206   // Synchronizes accesses to |callbacks_|.
207   SchedulerLock lock_;
208 
209   // List of callbacks to run on destruction.
210   std::vector<OnceClosure> callbacks_;
211 
212   DISALLOW_COPY_AND_ASSIGN(ScopedLazyTaskRunnerListForTesting);
213 };
214 
215 }  // namespace internal
216 }  // namespace base
217 
218 #endif  // BASE_TASK_SCHEDULER_LAZY_TASK_RUNNER_H_
219