// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_TASK_LAZY_THREAD_POOL_TASK_RUNNER_H_ #define BASE_TASK_LAZY_THREAD_POOL_TASK_RUNNER_H_ #include #include #include "base/base_export.h" #include "base/callback.h" #include "base/task/common/checked_lock.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" #include "base/task/single_thread_task_runner_thread_mode.h" #include "base/task/task_traits.h" #include "base/thread_annotations.h" #include "build/build_config.h" // Lazy(Sequenced|SingleThread|COMSTA)TaskRunner lazily creates a TaskRunner. // // Lazy(Sequenced|SingleThread|COMSTA)TaskRunner is meant to be instantiated in // an anonymous namespace (no static initializer is generated) and used to post // tasks to the same thread-pool-bound sequence/thread from pieces of code that // don't have a better way of sharing a TaskRunner. It is important to use this // class instead of a self-managed global variable or LazyInstance so that the // TaskRunners do not outlive the scope of the TaskEnvironment in unit tests // (otherwise the next test in the same process will die in use-after-frees). // // IMPORTANT: Only use this API as a last resort. Prefer storing a // (Sequenced|SingleThread)TaskRunner returned by // base::ThreadPool::Create(Sequenced|SingleThread|COMSTA)TaskRunner() as a // member on an object accessible by all PostTask() call sites. // // Example usage 1: // // namespace { // base::LazyThreadPoolSequencedTaskRunner g_sequenced_task_runner = // LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER( // base::TaskTraits(base::MayBlock(), // base::TaskPriority::USER_VISIBLE)); // } // namespace // // void SequencedFunction() { // // Different invocations of this function post to the same // // MayBlock() SequencedTaskRunner. // g_sequenced_task_runner.Get()->PostTask(FROM_HERE, base::BindOnce(...)); // } // // Example usage 2: // // namespace { // base::LazyThreadPoolSequencedTaskRunner g_sequenced_task_task_runner = // LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER( // base::TaskTraits(base::MayBlock())); // } // namespace // // // Code from different files can access the SequencedTaskRunner via this // // function. // scoped_refptr GetTaskRunner() { // return g_sequenced_task_runner.Get(); // } namespace base { namespace internal { template class BASE_EXPORT LazyThreadPoolTaskRunner; } // namespace internal // Lazy SequencedTaskRunner. using LazyThreadPoolSequencedTaskRunner = internal::LazyThreadPoolTaskRunner; // Lazy SingleThreadTaskRunner. using LazyThreadPoolSingleThreadTaskRunner = internal::LazyThreadPoolTaskRunner; #if BUILDFLAG(IS_WIN) // Lazy COM-STA enabled SingleThreadTaskRunner. using LazyThreadPoolCOMSTATaskRunner = internal::LazyThreadPoolTaskRunner; #endif // Helper macros to generate a variable name by concatenation. #define LAZY_TASK_RUNNER_CONCATENATE_INTERNAL2(a, b) a##b #define LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(a, b) \ LAZY_TASK_RUNNER_CONCATENATE_INTERNAL2(a, b) // Use the macros below to initialize a LazyThreadPoolTaskRunner. These macros // verify that their arguments are constexpr, which is important to prevent the // generation of a static initializer. // |traits| are TaskTraits used when creating the SequencedTaskRunner. #define LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(traits) \ base::LazyThreadPoolSequencedTaskRunner::CreateInternal(traits); \ [[maybe_unused]] constexpr base::TaskTraits \ LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyTraitsAreConstexpr, \ __LINE__) = traits // |traits| are TaskTraits used when creating the SingleThreadTaskRunner. // |thread_mode| specifies whether the SingleThreadTaskRunner can share its // thread with other SingleThreadTaskRunners. #define LAZY_THREAD_POOL_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(traits, \ thread_mode) \ base::LazyThreadPoolSingleThreadTaskRunner::CreateInternal(traits, \ thread_mode); \ [[maybe_unused]] constexpr base::TaskTraits \ LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyTraitsAreConstexpr, \ __LINE__) = traits; \ [[maybe_unused]] constexpr base::SingleThreadTaskRunnerThreadMode \ LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyThreadModeIsConstexpr, \ __LINE__) = thread_mode // |traits| are TaskTraits used when creating the COM STA // SingleThreadTaskRunner. |thread_mode| specifies whether the COM STA // SingleThreadTaskRunner can share its thread with other // SingleThreadTaskRunners. #define LAZY_COM_STA_TASK_RUNNER_INITIALIZER(traits, thread_mode) \ base::LazyThreadPoolCOMSTATaskRunner::CreateInternal(traits, thread_mode); \ [[maybe_unused]] constexpr base::TaskTraits \ LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyTraitsAreConstexpr, \ __LINE__) = traits; \ [[maybe_unused]] constexpr base::SingleThreadTaskRunnerThreadMode \ LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyThreadModeIsConstexpr, \ __LINE__) = thread_mode namespace internal { template class BASE_EXPORT LazyThreadPoolTaskRunner { public: // Use the macros above rather than a direct call to this. // // |traits| are TaskTraits to use to create the TaskRunner. If this // LazyThreadPoolTaskRunner is specialized to create a SingleThreadTaskRunner, // |thread_mode| specifies whether the SingleThreadTaskRunner can share its // thread with other SingleThreadTaskRunner. Otherwise, it is unused. static constexpr LazyThreadPoolTaskRunner CreateInternal( const TaskTraits& traits, SingleThreadTaskRunnerThreadMode thread_mode = SingleThreadTaskRunnerThreadMode::SHARED) { return LazyThreadPoolTaskRunner(traits, thread_mode); } // Returns the TaskRunner held by this instance. Creates it if it didn't // already exist. Thread-safe. scoped_refptr Get(); private: constexpr LazyThreadPoolTaskRunner( const TaskTraits& traits, SingleThreadTaskRunnerThreadMode thread_mode = SingleThreadTaskRunnerThreadMode::SHARED) : traits_(traits), thread_mode_(thread_mode) {} // Releases the TaskRunner held by this instance. void Reset(); // Creates and returns a new TaskRunner. scoped_refptr Create(); // Creates a new TaskRunner via Create(), adds an explicit ref to it, and // returns it raw. Used as an adapter for lazy instance helpers. Static and // takes |this| as an explicit param to match the void* signature of // GetOrCreateLazyPointer(). static TaskRunnerType* CreateRaw(void* void_self); // TaskTraits to create the TaskRunner. const TaskTraits traits_; // SingleThreadTaskRunnerThreadMode to create the TaskRunner. const SingleThreadTaskRunnerThreadMode thread_mode_; // Can have 3 states: // - This instance does not hold a TaskRunner: 0 // - This instance is creating a TaskRunner: kLazyInstanceStateCreating // - This instance holds a TaskRunner: Pointer to the TaskRunner. // LazyInstance's internals are reused to handle transition between states. std::atomic state_ = 0; // No DISALLOW_COPY_AND_ASSIGN since that prevents static initialization with // Visual Studio (warning C4592: 'symbol will be dynamically initialized // (implementation limitation))'. }; // When a LazyThreadPoolTaskRunner becomes active (invokes Get()), it adds a // callback to the current ScopedLazyTaskRunnerListForTesting, if any. // Callbacks run when the ScopedLazyTaskRunnerListForTesting is // destroyed. In a test process, a ScopedLazyTaskRunnerListForTesting // must be instantiated before any LazyThreadPoolTaskRunner becomes active. class BASE_EXPORT ScopedLazyTaskRunnerListForTesting { public: ScopedLazyTaskRunnerListForTesting(); ScopedLazyTaskRunnerListForTesting( const ScopedLazyTaskRunnerListForTesting&) = delete; ScopedLazyTaskRunnerListForTesting& operator=( const ScopedLazyTaskRunnerListForTesting&) = delete; ~ScopedLazyTaskRunnerListForTesting(); private: friend class LazyThreadPoolTaskRunner; friend class LazyThreadPoolTaskRunner; #if BUILDFLAG(IS_WIN) friend class LazyThreadPoolTaskRunner; #endif // Add |callback| to the list of callbacks to run on destruction. void AddCallback(OnceClosure callback); CheckedLock lock_; // List of callbacks to run on destruction. std::vector callbacks_ GUARDED_BY(lock_); }; } // namespace internal } // namespace base #endif // BASE_TASK_LAZY_THREAD_POOL_TASK_RUNNER_H_