| // Copyright 2017 The Chromium Authors | |
| // 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 <atomic> | |
| #include <vector> | |
| #include "base/base_export.h" | |
| #include "base/functional/callback.h" | |
| #include "base/macros/uniquify.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<base::SequencedTaskRunner> GetTaskRunner() { | |
| // return g_sequenced_task_runner.Get(); | |
| // } | |
| namespace base { | |
| namespace internal { | |
| template <typename TaskRunnerType, bool com_sta> | |
| class BASE_EXPORT LazyThreadPoolTaskRunner; | |
| } // namespace internal | |
| // Lazy SequencedTaskRunner. | |
| using LazyThreadPoolSequencedTaskRunner = | |
| internal::LazyThreadPoolTaskRunner<SequencedTaskRunner, false>; | |
| // Lazy SingleThreadTaskRunner. | |
| using LazyThreadPoolSingleThreadTaskRunner = | |
| internal::LazyThreadPoolTaskRunner<SingleThreadTaskRunner, false>; | |
| #if BUILDFLAG(IS_WIN) | |
| // Lazy COM-STA enabled SingleThreadTaskRunner. | |
| using LazyThreadPoolCOMSTATaskRunner = | |
| internal::LazyThreadPoolTaskRunner<SingleThreadTaskRunner, true>; | |
| #endif | |
| // 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 BASE_UNIQUIFY( \ | |
| kVerifyTraitsAreConstexpr) = 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 BASE_UNIQUIFY( \ | |
| kVerifyTraitsAreConstexpr) = traits; \ | |
| [[maybe_unused]] constexpr base::SingleThreadTaskRunnerThreadMode \ | |
| BASE_UNIQUIFY(kVerifyThreadModeIsConstexpr) = 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 BASE_UNIQUIFY( \ | |
| kVerifyTraitsAreConstexpr) = traits; \ | |
| [[maybe_unused]] constexpr base::SingleThreadTaskRunnerThreadMode \ | |
| BASE_UNIQUIFY(kVerifyThreadModeIsConstexpr) = thread_mode | |
| namespace internal { | |
| template <typename TaskRunnerType, bool com_sta> | |
| 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<TaskRunnerType> 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<TaskRunnerType> 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<uintptr_t> 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<SequencedTaskRunner, false>; | |
| friend class LazyThreadPoolTaskRunner<SingleThreadTaskRunner, false>; | |
| #if BUILDFLAG(IS_WIN) | |
| friend class LazyThreadPoolTaskRunner<SingleThreadTaskRunner, true>; | |
| #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<OnceClosure> callbacks_ GUARDED_BY(lock_); | |
| }; | |
| } // namespace internal | |
| } // namespace base | |
| #endif // BASE_TASK_LAZY_THREAD_POOL_TASK_RUNNER_H_ |