| // 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<SingleThreadTaskRunner>& |
| 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<SingleThreadTaskRunner> task_runner); |
| |
| CurrentDefaultHandle(const CurrentDefaultHandle&) = delete; |
| CurrentDefaultHandle& operator=(const CurrentDefaultHandle&) = delete; |
| |
| ~CurrentDefaultHandle(); |
| |
| private: |
| friend class SingleThreadTaskRunner; |
| friend class CurrentHandleOverride; |
| |
| const AutoReset<CurrentDefaultHandle*> resetter_; |
| |
| scoped_refptr<SingleThreadTaskRunner> 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<SingleThreadTaskRunner> overriding_task_runner, |
| bool allow_nested_runloop = false); |
| |
| absl::optional<SingleThreadTaskRunner::CurrentDefaultHandle> |
| top_level_thread_task_runner_current_default_; |
| |
| scoped_refptr<SingleThreadTaskRunner> 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<ScopedDisallowRunningRunLoop> 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<SingleThreadTaskRunner> 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_ |