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