• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors. All rights reserved.
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 #include "third_party/abseil-cpp/absl/base/attributes.h"
18 
19 namespace base {
20 
21 namespace {
22 
23 ABSL_CONST_INIT thread_local SingleThreadTaskRunner::CurrentDefaultHandle*
24     current_default_handle = nullptr;
25 
26 // This function can be removed, and the calls below replaced with direct
27 // variable accesses, once the MSAN workaround is not necessary.
GetCurrentDefaultHandle()28 SingleThreadTaskRunner::CurrentDefaultHandle* GetCurrentDefaultHandle() {
29   // Workaround false-positive MSAN use-of-uninitialized-value on
30   // thread_local storage for loaded libraries:
31   // https://github.com/google/sanitizers/issues/1265
32   MSAN_UNPOISON(&current_default_handle,
33                 sizeof(SingleThreadTaskRunner::CurrentDefaultHandle*));
34 
35   return current_default_handle;
36 }
37 
38 }  // namespace
39 
40 // static
41 const scoped_refptr<SingleThreadTaskRunner>&
GetCurrentDefault()42 SingleThreadTaskRunner::GetCurrentDefault() {
43   const auto* const handle = GetCurrentDefaultHandle();
44   CHECK(handle)
45       << "Error: This caller requires a single-threaded context (i.e. the "
46          "current task needs to run from a SingleThreadTaskRunner). If you're "
47          "in a test refer to //docs/threading_and_tasks_testing.md."
48       << (SequencedTaskRunner::HasCurrentDefault()
49               ? " Note: base::SequencedTaskRunner::GetCurrentDefault() "
50                 "is set; "
51                 "consider using it if the current task can run from a "
52                 "SequencedTaskRunner."
53               : "");
54   return handle->task_runner_;
55 }
56 
57 // static
HasCurrentDefault()58 bool SingleThreadTaskRunner::HasCurrentDefault() {
59   return !!GetCurrentDefaultHandle();
60 }
61 
CurrentDefaultHandle(scoped_refptr<SingleThreadTaskRunner> task_runner)62 SingleThreadTaskRunner::CurrentDefaultHandle::CurrentDefaultHandle(
63     scoped_refptr<SingleThreadTaskRunner> task_runner)
64     : resetter_(&current_default_handle, this, nullptr),
65       task_runner_(std::move(task_runner)),
66       sequenced_task_runner_current_default_(task_runner_) {
67   DCHECK(task_runner_->BelongsToCurrentThread());
68 }
69 
~CurrentDefaultHandle()70 SingleThreadTaskRunner::CurrentDefaultHandle::~CurrentDefaultHandle() {
71   DCHECK(task_runner_->BelongsToCurrentThread());
72   DCHECK_EQ(GetCurrentDefaultHandle(), this);
73 }
74 
CurrentHandleOverride(scoped_refptr<SingleThreadTaskRunner> overriding_task_runner,bool allow_nested_runloop)75 SingleThreadTaskRunner::CurrentHandleOverride::CurrentHandleOverride(
76     scoped_refptr<SingleThreadTaskRunner> overriding_task_runner,
77     bool allow_nested_runloop) {
78   DCHECK(!SequencedTaskRunner::HasCurrentDefault() ||
79          SingleThreadTaskRunner::HasCurrentDefault())
80       << "SingleThreadTaskRunner::CurrentHandleOverride is not compatible with "
81          "a SequencedTaskRunner::CurrentDefaultHandle already "
82          "being set on this thread (except when it's "
83          "set by the current "
84          "SingleThreadTaskRunner::CurrentDefaultHandle).";
85 
86   if (!SingleThreadTaskRunner::HasCurrentDefault()) {
87     top_level_thread_task_runner_current_default_.emplace(
88         std::move(overriding_task_runner));
89     return;
90   }
91 
92 #if DCHECK_IS_ON()
93   expected_task_runner_before_restore_ = overriding_task_runner.get();
94 #endif
95   auto* const handle = GetCurrentDefaultHandle();
96   SequencedTaskRunner::SetCurrentDefaultHandleTaskRunner(
97       handle->sequenced_task_runner_current_default_, overriding_task_runner);
98   handle->task_runner_.swap(overriding_task_runner);
99   // Due to the swap, now `handle->task_runner_` points to the overriding task
100   // runner and `overriding_task_runner_` points to the previous task runner.
101   task_runner_to_restore_ = std::move(overriding_task_runner);
102 
103   if (!allow_nested_runloop) {
104     no_running_during_override_ =
105         std::make_unique<ScopedDisallowRunningRunLoop>();
106   }
107 }
108 
~CurrentHandleOverride()109 SingleThreadTaskRunner::CurrentHandleOverride::~CurrentHandleOverride() {
110   if (task_runner_to_restore_) {
111     auto* const handle = GetCurrentDefaultHandle();
112 #if DCHECK_IS_ON()
113     DCHECK_EQ(expected_task_runner_before_restore_, handle->task_runner_.get())
114         << "Nested overrides must expire their "
115            "SingleThreadTaskRunner::CurrentHandleOverride "
116            "in LIFO order.";
117 #endif
118 
119     SequencedTaskRunner::SetCurrentDefaultHandleTaskRunner(
120         handle->sequenced_task_runner_current_default_,
121         task_runner_to_restore_);
122     handle->task_runner_.swap(task_runner_to_restore_);
123   }
124 }
125 
126 }  // namespace base
127