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