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/threading/thread_task_runner_handle.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/run_loop.h"
14 #include "base/threading/sequenced_task_runner_handle.h"
15 #include "base/threading/thread_local.h"
16
17 namespace base {
18
19 namespace {
20
21 base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle>>::Leaky
22 thread_task_runner_tls = LAZY_INSTANCE_INITIALIZER;
23
24 } // namespace
25
26 // static
Get()27 scoped_refptr<SingleThreadTaskRunner> ThreadTaskRunnerHandle::Get() {
28 ThreadTaskRunnerHandle* current = thread_task_runner_tls.Pointer()->Get();
29 CHECK(current) << "Error: This caller requires a single-threaded context "
30 "(i.e. the current task needs to run from a "
31 "SingleThreadTaskRunner).";
32 return current->task_runner_;
33 }
34
35 // static
IsSet()36 bool ThreadTaskRunnerHandle::IsSet() {
37 return !!thread_task_runner_tls.Pointer()->Get();
38 }
39
40 // static
OverrideForTesting(scoped_refptr<SingleThreadTaskRunner> overriding_task_runner)41 ScopedClosureRunner ThreadTaskRunnerHandle::OverrideForTesting(
42 scoped_refptr<SingleThreadTaskRunner> overriding_task_runner) {
43 // OverrideForTesting() is not compatible with a SequencedTaskRunnerHandle
44 // being set (but SequencedTaskRunnerHandle::IsSet() includes
45 // ThreadTaskRunnerHandle::IsSet() so that's discounted as the only valid
46 // excuse for it to be true). Sadly this means that tests that merely need a
47 // SequencedTaskRunnerHandle on their main thread can be forced to use a
48 // ThreadTaskRunnerHandle if they're also using test task runners (that
49 // OverrideForTesting() when running their tasks from said main thread). To
50 // solve this: sequence_task_runner_handle.cc and thread_task_runner_handle.cc
51 // would have to be merged into a single impl file and share TLS state. This
52 // was deemed unecessary for now as most tests should use higher level
53 // constructs and not have to instantiate task runner handles on their own.
54 DCHECK(!SequencedTaskRunnerHandle::IsSet() || IsSet());
55
56 if (!IsSet()) {
57 auto top_level_ttrh = std::make_unique<ThreadTaskRunnerHandle>(
58 std::move(overriding_task_runner));
59 return ScopedClosureRunner(base::BindOnce(
60 [](std::unique_ptr<ThreadTaskRunnerHandle> ttrh_to_release) {},
61 std::move(top_level_ttrh)));
62 }
63
64 ThreadTaskRunnerHandle* ttrh = thread_task_runner_tls.Pointer()->Get();
65 // Swap the two (and below bind |overriding_task_runner|, which is now the
66 // previous one, as the |task_runner_to_restore|).
67 ttrh->task_runner_.swap(overriding_task_runner);
68
69 auto no_running_during_override =
70 std::make_unique<RunLoop::ScopedDisallowRunningForTesting>();
71
72 return ScopedClosureRunner(base::BindOnce(
73 [](scoped_refptr<SingleThreadTaskRunner> task_runner_to_restore,
74 SingleThreadTaskRunner* expected_task_runner_before_restore,
75 std::unique_ptr<RunLoop::ScopedDisallowRunningForTesting>
76 no_running_during_override) {
77 ThreadTaskRunnerHandle* ttrh = thread_task_runner_tls.Pointer()->Get();
78
79 DCHECK_EQ(expected_task_runner_before_restore, ttrh->task_runner_.get())
80 << "Nested overrides must expire their ScopedClosureRunners "
81 "in LIFO order.";
82
83 ttrh->task_runner_.swap(task_runner_to_restore);
84 },
85 std::move(overriding_task_runner),
86 base::Unretained(ttrh->task_runner_.get()),
87 std::move(no_running_during_override)));
88 }
89
ThreadTaskRunnerHandle(scoped_refptr<SingleThreadTaskRunner> task_runner)90 ThreadTaskRunnerHandle::ThreadTaskRunnerHandle(
91 scoped_refptr<SingleThreadTaskRunner> task_runner)
92 : task_runner_(std::move(task_runner)) {
93 DCHECK(task_runner_->BelongsToCurrentThread());
94 // No SequencedTaskRunnerHandle (which includes ThreadTaskRunnerHandles)
95 // should already be set for this thread.
96 DCHECK(!SequencedTaskRunnerHandle::IsSet());
97 thread_task_runner_tls.Pointer()->Set(this);
98 }
99
~ThreadTaskRunnerHandle()100 ThreadTaskRunnerHandle::~ThreadTaskRunnerHandle() {
101 DCHECK(task_runner_->BelongsToCurrentThread());
102 DCHECK_EQ(thread_task_runner_tls.Pointer()->Get(), this);
103 thread_task_runner_tls.Pointer()->Set(nullptr);
104 }
105
106 } // namespace base
107