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