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