// 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_SCHEDULER_LAZY_TASK_RUNNER_H_ #define BASE_TASK_SCHEDULER_LAZY_TASK_RUNNER_H_ #include #include "base/atomicops.h" #include "base/callback.h" #include "base/compiler_specific.h" #include "base/lazy_instance.h" #include "base/sequenced_task_runner.h" #include "base/single_thread_task_runner.h" #include "base/task_scheduler/scheduler_lock.h" #include "base/task_scheduler/single_thread_task_runner_thread_mode.h" #include "base/task_scheduler/task_traits.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 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 ScopedTaskEnvironment 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::Create(Sequenced|SingleThread|COMSTA)TaskRunnerWithTraits() as a member // on an object accessible by all PostTask() call sites. // // Example usage 1: // // namespace { // base::LazySequencedTaskRunner g_sequenced_task_runner = // LAZY_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::LazySequencedTaskRunner g_sequenced_task_task_runner = // LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({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 LazyTaskRunner; } // namespace internal // Lazy SequencedTaskRunner. using LazySequencedTaskRunner = internal::LazyTaskRunner; // Lazy SingleThreadTaskRunner. using LazySingleThreadTaskRunner = internal::LazyTaskRunner; #if defined(OS_WIN) // Lazy COM-STA enabled SingleThreadTaskRunner. using LazyCOMSTATaskRunner = internal::LazyTaskRunner; #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 LazyTaskRunner. 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_SEQUENCED_TASK_RUNNER_INITIALIZER(traits) \ base::LazySequencedTaskRunner::CreateInternal(traits); \ ALLOW_UNUSED_TYPE 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_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(traits, thread_mode) \ base::LazySingleThreadTaskRunner::CreateInternal(traits, thread_mode); \ ALLOW_UNUSED_TYPE constexpr base::TaskTraits \ LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyTraitsAreConstexpr, \ __LINE__) = traits; \ ALLOW_UNUSED_TYPE 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::LazyCOMSTATaskRunner::CreateInternal(traits, thread_mode); \ ALLOW_UNUSED_TYPE constexpr base::TaskTraits \ LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyTraitsAreConstexpr, \ __LINE__) = traits; \ ALLOW_UNUSED_TYPE constexpr base::SingleThreadTaskRunnerThreadMode \ LAZY_TASK_RUNNER_CONCATENATE_INTERNAL(kVerifyThreadModeIsConstexpr, \ __LINE__) = thread_mode namespace internal { template class BASE_EXPORT LazyTaskRunner { public: // Use the macros above rather than a direct call to this. // // |traits| are TaskTraits to use to create the TaskRunner. If this // LazyTaskRunner 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 LazyTaskRunner CreateInternal( const TaskTraits& traits, SingleThreadTaskRunnerThreadMode thread_mode = SingleThreadTaskRunnerThreadMode::SHARED) { return LazyTaskRunner(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 LazyTaskRunner(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(); // 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. subtle::AtomicWord 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 LazyTaskRunner 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 // LazyTaskRunner becomes active. class BASE_EXPORT ScopedLazyTaskRunnerListForTesting { public: ScopedLazyTaskRunnerListForTesting(); ~ScopedLazyTaskRunnerListForTesting(); private: friend class LazyTaskRunner; friend class LazyTaskRunner; #if defined(OS_WIN) friend class LazyTaskRunner; #endif // Add |callback| to the list of callbacks to run on destruction. void AddCallback(OnceClosure callback); // Synchronizes accesses to |callbacks_|. SchedulerLock lock_; // List of callbacks to run on destruction. std::vector callbacks_; DISALLOW_COPY_AND_ASSIGN(ScopedLazyTaskRunnerListForTesting); }; } // namespace internal } // namespace base #endif // BASE_TASK_SCHEDULER_LAZY_TASK_RUNNER_H_