// Copyright 2012 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_SINGLE_THREAD_TASK_RUNNER_H_ #define BASE_TASK_SINGLE_THREAD_TASK_RUNNER_H_ #include "base/auto_reset.h" #include "base/base_export.h" #include "base/dcheck_is_on.h" #include "base/memory/raw_ptr_exclusion.h" #include "base/task/sequenced_task_runner.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace blink::scheduler { class MainThreadSchedulerImpl; } // namespace blink::scheduler namespace base { class ScopedDisallowRunningRunLoop; // A SingleThreadTaskRunner is a SequencedTaskRunner with one more // guarantee; namely, that all tasks are run on a single dedicated // thread. Most use cases require only a SequencedTaskRunner, unless // there is a specific need to run tasks on only a single thread. // // SingleThreadTaskRunner implementations might: // - Post tasks to an existing thread's MessageLoop (see // MessageLoop::task_runner()). // - Create their own worker thread and MessageLoop to post tasks to. // - Add tasks to a FIFO and signal to a non-MessageLoop thread for them to // be processed. This allows TaskRunner-oriented code run on threads // running other kinds of message loop, e.g. Jingle threads. class BASE_EXPORT SingleThreadTaskRunner : public SequencedTaskRunner { public: // A more explicit alias to RunsTasksInCurrentSequence(). bool BelongsToCurrentThread() const { return RunsTasksInCurrentSequence(); } // Returns the default SingleThreadTaskRunner for the current thread. // On threads that service multiple task queues, the default task queue is // preferred to inheriting the current task queue (otherwise, everything would // implicitly be "input priority"...). If the caller knows which task queue it // should be running on, it should post to that SingleThreadTaskRunner // directly instead of GetCurrentDefault(). This is critical in some // cases, e.g. DeleteSoon or RefCountedDeleteOnSequence should delete the // object on the same task queue it's used from (or on a lower priority). // // DCHECKs if the current thread isn't servicing a SingleThreadTaskRunner. // // See // https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md#Posting-to-the-Current-Virtual_Thread // for details [[nodiscard]] static const scoped_refptr& GetCurrentDefault(); // Returns true if the SingleThreadTaskRunner is already created for // the current thread. [[nodiscard]] static bool HasCurrentDefault(); class CurrentHandleOverride; class CurrentHandleOverrideForTesting; class BASE_EXPORT CurrentDefaultHandle { public: // Binds |task_runner| to the current thread. |task_runner| must belong // to the current thread. explicit CurrentDefaultHandle( scoped_refptr task_runner); CurrentDefaultHandle(const CurrentDefaultHandle&) = delete; CurrentDefaultHandle& operator=(const CurrentDefaultHandle&) = delete; ~CurrentDefaultHandle(); private: friend class SingleThreadTaskRunner; friend class CurrentHandleOverride; const AutoReset resetter_; scoped_refptr task_runner_; // Registers |task_runner_|'s SequencedTaskRunner interface as the // SequencedTaskRunner::CurrentDefaultHandle on this thread. SequencedTaskRunner::CurrentDefaultHandle sequenced_task_runner_current_default_; }; // CurrentHandleOverride overrides the task runner returned by // |SingleThreadTaskRunner::GetCurrentDefault()| to point at // |overriding_task_runner| until the |CurrentHandleOverride| goes out of // scope. CurrentHandleOverride instantiates a new SingleThreadTaskRunner if // SingleThreadTaskRunner is not instantiated on the current thread. Nested // overrides are allowed but callers must ensure the |CurrentHandleOverride|s // expire in LIFO (stack) order. // // Note: nesting SingleThreadTaskRunner is subtle and should be done with // care, hence the need to friend and request a //base/OWNERS review for usage // outside of tests. Use CurrentHandleOverrideForTesting to bypass the friend // requirement in tests. class BASE_EXPORT CurrentHandleOverride { public: CurrentHandleOverride(const CurrentHandleOverride&) = delete; CurrentHandleOverride& operator=(const CurrentHandleOverride&) = delete; ~CurrentHandleOverride(); private: friend class CurrentHandleOverrideForTesting; FRIEND_TEST_ALL_PREFIXES(SingleThreadTaskRunnerCurrentDefaultHandleTest, NestedRunLoop); // We expect SingleThreadTaskRunner::CurrentHandleOverride to be only needed // under special circumstances. Require them to be enumerated as friends to // require //base/OWNERS review. Use // SingleTaskRunner::CurrentHandleOverrideForTesting in unit tests to avoid // the friend requirement. friend class blink::scheduler::MainThreadSchedulerImpl; // Constructs a SingleThreadTaskRunner::CurrentHandleOverride which will // make SingleThreadTaskRunner::GetCurrentDefault() return // |overriding_task_runner| for its lifetime. |allow_nested_loop| specifies // whether RunLoop::Run() is allowed during this override's lifetime. It's // not recommended to allow this unless the current thread's scheduler // guarantees that only tasks which pertain to |overriding_task_runner|'s // context will be run by nested RunLoops. explicit CurrentHandleOverride( scoped_refptr overriding_task_runner, bool allow_nested_runloop = false); absl::optional top_level_thread_task_runner_current_default_; scoped_refptr task_runner_to_restore_; #if DCHECK_IS_ON() // This field is not a raw_ptr<> because it was filtered by the rewriter // for: #union RAW_PTR_EXCLUSION SingleThreadTaskRunner* expected_task_runner_before_restore_{nullptr}; #endif std::unique_ptr no_running_during_override_; }; // Note: nesting CurrentHandleOverrides isn't generally desired but it's // useful in some unit tests where multiple task runners share the main thread // for simplicity and determinism. Only use this when no other constructs will // work (see base/test/task_environment.h and // base/test/test_mock_time_task_runner.h for preferred alternatives). class BASE_EXPORT CurrentHandleOverrideForTesting { public: explicit CurrentHandleOverrideForTesting( scoped_refptr overriding_task_runner) : thread_task_runner_current_override_( std::move(overriding_task_runner)) {} private: CurrentHandleOverride thread_task_runner_current_override_; }; protected: ~SingleThreadTaskRunner() override = default; }; } // namespace base #endif // BASE_TASK_SINGLE_THREAD_TASK_RUNNER_H_