blob: 6659824097cfd5bb2c2104a5339cc1bacf6bd049 [file] [log] [blame]
// 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 <optional>
#include "base/auto_reset.h"
#include "base/base_export.h"
#include "base/dcheck_is_on.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/task/sequenced_task_runner.h"
namespace blink::scheduler {
class MainThreadSchedulerImpl;
} // namespace blink::scheduler
namespace base::sequence_manager::internal {
class CurrentDefaultHandleOverrideForRunOrPostTask;
}
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:
// Returns true if the `SingleThreadTaskRunner` runs tasks posted to it on the
// current thread.
//
// Identical to `RunsTaskInCurrentSequence()`, except from a `RunOrPostTask()`
// callback running synchronously (in that case, `BelongsToCurrentThread()`
// returns false and `RunsTaskInCurrentSequence()` returns true).
virtual bool BelongsToCurrentThread() const;
// 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 CurrentHandleOverrideForTesting;
class BASE_EXPORT CurrentDefaultHandle {
public:
// Sets the value returned by `SingleThreadTaskRunner::GetCurrentDefault()`
// and `SequencedTaskRunner::GetCurrentDefault()` to `task_runner` within
// its scope. `task_runner` must belong to the current thread. There must
// not already be a current default `SingleThreadTaskRunner` on this thread.
explicit CurrentDefaultHandle(
scoped_refptr<SingleThreadTaskRunner> task_runner);
CurrentDefaultHandle(const CurrentDefaultHandle&) = delete;
CurrentDefaultHandle& operator=(const CurrentDefaultHandle&) = delete;
~CurrentDefaultHandle();
private:
friend class SingleThreadTaskRunner;
// Overriding an existing current default SingleThreadTaskRunner should only
// be needed under special circumstances. Require them to be enumerated as
// friends to require //base/OWNERS review. Use
// SingleThreadTaskRunner::CurrentHandleOverrideForTesting in unit tests to
// avoid the friend requirement.
friend class blink::scheduler::MainThreadSchedulerImpl;
friend class CurrentHandleOverrideForTesting;
friend class sequence_manager::internal::
CurrentDefaultHandleOverrideForRunOrPostTask;
FRIEND_TEST_ALL_PREFIXES(SingleThreadTaskRunnerCurrentDefaultHandleTest,
NestedRunLoopAllowedUnderHandleOverride);
FRIEND_TEST_ALL_PREFIXES(SingleThreadTaskRunnerCurrentDefaultHandleTest,
NestedOverrideWithMayAlreadyExist);
FRIEND_TEST_ALL_PREFIXES(SingleThreadTaskRunnerCurrentDefaultHandleTest,
OverrideWithNull);
FRIEND_TEST_ALL_PREFIXES(SingleThreadTaskRunnerCurrentDefaultHandleTest,
OverrideWithNonNull);
struct MayAlreadyExist {};
// Same as the public constructor, but there may already be a current
// default `SingleThreadTaskRunner` on this thread.
CurrentDefaultHandle(scoped_refptr<SingleThreadTaskRunner> task_runner,
MayAlreadyExist);
scoped_refptr<SingleThreadTaskRunner> task_runner_;
raw_ptr<CurrentDefaultHandle> previous_handle_;
SequencedTaskRunner::CurrentDefaultHandle sequenced_handle_;
};
// Overrides the current default `SingleThreadTaskRunner` and disables running
// a `RunLoop` within its scope.
//
// Note: Overriding the current default SingleThreadTaskRunner 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);
~CurrentHandleOverrideForTesting();
private:
CurrentDefaultHandle current_default_handle_;
std::unique_ptr<ScopedDisallowRunningRunLoop> no_running_during_override_;
};
protected:
~SingleThreadTaskRunner() override = default;
};
} // namespace base
#endif // BASE_TASK_SINGLE_THREAD_TASK_RUNNER_H_