1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/task/single_thread_task_runner.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/check.h"
11 #include "base/check_op.h"
12 #include "base/compiler_specific.h"
13 #include "base/dcheck_is_on.h"
14 #include "base/functional/bind.h"
15 #include "base/lazy_instance.h"
16 #include "base/run_loop.h"
17
18 namespace base {
19
20 namespace {
21
22 constinit thread_local SingleThreadTaskRunner::CurrentDefaultHandle*
23 current_default_handle = nullptr;
24
25 // This function can be removed, and the calls below replaced with direct
26 // variable accesses, once the MSAN workaround is not necessary.
GetCurrentDefaultHandle()27 SingleThreadTaskRunner::CurrentDefaultHandle* GetCurrentDefaultHandle() {
28 // Workaround false-positive MSAN use-of-uninitialized-value on
29 // thread_local storage for loaded libraries:
30 // https://github.com/google/sanitizers/issues/1265
31 MSAN_UNPOISON(¤t_default_handle,
32 sizeof(SingleThreadTaskRunner::CurrentDefaultHandle*));
33
34 return current_default_handle;
35 }
36
37 } // namespace
38
BelongsToCurrentThread() const39 bool SingleThreadTaskRunner::BelongsToCurrentThread() const {
40 return RunsTasksInCurrentSequence();
41 }
42
43 // static
44 const scoped_refptr<SingleThreadTaskRunner>&
GetCurrentDefault()45 SingleThreadTaskRunner::GetCurrentDefault() {
46 const auto* const handle = GetCurrentDefaultHandle();
47 CHECK(handle && handle->task_runner_)
48 << "Error: This caller requires a single-threaded context (i.e. the "
49 "current task needs to run from a SingleThreadTaskRunner). If you're "
50 "in a test refer to //docs/threading_and_tasks_testing.md."
51 << (SequencedTaskRunner::HasCurrentDefault()
52 ? " Note: base::SequencedTaskRunner::GetCurrentDefault() "
53 "is set; "
54 "consider using it if the current task can run from a "
55 "SequencedTaskRunner."
56 : "");
57 return handle->task_runner_;
58 }
59
60 // static
HasCurrentDefault()61 bool SingleThreadTaskRunner::HasCurrentDefault() {
62 return !!GetCurrentDefaultHandle() &&
63 !!GetCurrentDefaultHandle()->task_runner_;
64 }
65
CurrentDefaultHandle(scoped_refptr<SingleThreadTaskRunner> task_runner)66 SingleThreadTaskRunner::CurrentDefaultHandle::CurrentDefaultHandle(
67 scoped_refptr<SingleThreadTaskRunner> task_runner)
68 : CurrentDefaultHandle(std::move(task_runner), MayAlreadyExist{}) {
69 CHECK(!previous_handle_ || !previous_handle_->task_runner_);
70 }
71
~CurrentDefaultHandle()72 SingleThreadTaskRunner::CurrentDefaultHandle::~CurrentDefaultHandle() {
73 DCHECK_EQ(GetCurrentDefaultHandle(), this);
74 current_default_handle = previous_handle_;
75 }
76
CurrentDefaultHandle(scoped_refptr<SingleThreadTaskRunner> task_runner,MayAlreadyExist)77 SingleThreadTaskRunner::CurrentDefaultHandle::CurrentDefaultHandle(
78 scoped_refptr<SingleThreadTaskRunner> task_runner,
79 MayAlreadyExist)
80 : task_runner_(std::move(task_runner)),
81 previous_handle_(GetCurrentDefaultHandle()),
82 sequenced_handle_(
83 task_runner_,
84 SequencedTaskRunner::CurrentDefaultHandle::MayAlreadyExist{}) {
85 // Support overriding the current default with a null task runner or a task
86 // runner that belongs to the current thread.
87 DCHECK(!task_runner_ || task_runner_->BelongsToCurrentThread());
88 current_default_handle = this;
89 }
90
91 SingleThreadTaskRunner::CurrentHandleOverrideForTesting::
CurrentHandleOverrideForTesting(scoped_refptr<SingleThreadTaskRunner> overriding_task_runner)92 CurrentHandleOverrideForTesting(
93 scoped_refptr<SingleThreadTaskRunner> overriding_task_runner)
94 : current_default_handle_(std::move(overriding_task_runner),
95 CurrentDefaultHandle::MayAlreadyExist{}),
96 no_running_during_override_(
97 std::make_unique<ScopedDisallowRunningRunLoop>()) {}
98
99 SingleThreadTaskRunner::CurrentHandleOverrideForTesting::
100 ~CurrentHandleOverrideForTesting() = default;
101
102 } // namespace base
103