171 lines
6.9 KiB
C
171 lines
6.9 KiB
C
|
|
// 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_
|