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