1 // Copyright (c) 2012 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_checker.h"
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/macros.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/sequence_token.h"
14 #include "base/test/gtest_util.h"
15 #include "base/test/test_simple_task_runner.h"
16 #include "base/threading/simple_thread.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace base {
21 namespace {
22
23 // A thread that runs a callback.
24 class RunCallbackThread : public SimpleThread {
25 public:
RunCallbackThread(const Closure & callback)26 explicit RunCallbackThread(const Closure& callback)
27 : SimpleThread("RunCallbackThread"), callback_(callback) {}
28
29 private:
30 // SimpleThread:
Run()31 void Run() override { callback_.Run(); }
32
33 const Closure callback_;
34
35 DISALLOW_COPY_AND_ASSIGN(RunCallbackThread);
36 };
37
38 // Runs a callback on a new thread synchronously.
RunCallbackOnNewThreadSynchronously(const Closure & callback)39 void RunCallbackOnNewThreadSynchronously(const Closure& callback) {
40 RunCallbackThread run_callback_thread(callback);
41 run_callback_thread.Start();
42 run_callback_thread.Join();
43 }
44
ExpectCalledOnValidThread(ThreadCheckerImpl * thread_checker)45 void ExpectCalledOnValidThread(ThreadCheckerImpl* thread_checker) {
46 ASSERT_TRUE(thread_checker);
47
48 // This should bind |thread_checker| to the current thread if it wasn't
49 // already bound to a thread.
50 EXPECT_TRUE(thread_checker->CalledOnValidThread());
51
52 // Since |thread_checker| is now bound to the current thread, another call to
53 // CalledOnValidThread() should return true.
54 EXPECT_TRUE(thread_checker->CalledOnValidThread());
55 }
56
ExpectNotCalledOnValidThread(ThreadCheckerImpl * thread_checker)57 void ExpectNotCalledOnValidThread(ThreadCheckerImpl* thread_checker) {
58 ASSERT_TRUE(thread_checker);
59 EXPECT_FALSE(thread_checker->CalledOnValidThread());
60 }
61
ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle(ThreadCheckerImpl * thread_checker,SequenceToken sequence_token)62 void ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle(
63 ThreadCheckerImpl* thread_checker,
64 SequenceToken sequence_token) {
65 ThreadTaskRunnerHandle thread_task_runner_handle(
66 MakeRefCounted<TestSimpleTaskRunner>());
67 ScopedSetSequenceTokenForCurrentThread
68 scoped_set_sequence_token_for_current_thread(sequence_token);
69 ExpectNotCalledOnValidThread(thread_checker);
70 }
71
72 } // namespace
73
TEST(ThreadCheckerTest,AllowedSameThreadNoSequenceToken)74 TEST(ThreadCheckerTest, AllowedSameThreadNoSequenceToken) {
75 ThreadCheckerImpl thread_checker;
76 EXPECT_TRUE(thread_checker.CalledOnValidThread());
77 }
78
TEST(ThreadCheckerTest,AllowedSameThreadAndSequenceDifferentTasksWithThreadTaskRunnerHandle)79 TEST(ThreadCheckerTest,
80 AllowedSameThreadAndSequenceDifferentTasksWithThreadTaskRunnerHandle) {
81 ThreadTaskRunnerHandle thread_task_runner_handle(
82 MakeRefCounted<TestSimpleTaskRunner>());
83
84 std::unique_ptr<ThreadCheckerImpl> thread_checker;
85 const SequenceToken sequence_token = SequenceToken::Create();
86
87 {
88 ScopedSetSequenceTokenForCurrentThread
89 scoped_set_sequence_token_for_current_thread(sequence_token);
90 thread_checker.reset(new ThreadCheckerImpl);
91 }
92
93 {
94 ScopedSetSequenceTokenForCurrentThread
95 scoped_set_sequence_token_for_current_thread(sequence_token);
96 EXPECT_TRUE(thread_checker->CalledOnValidThread());
97 }
98 }
99
TEST(ThreadCheckerTest,AllowedSameThreadSequenceAndTaskNoThreadTaskRunnerHandle)100 TEST(ThreadCheckerTest,
101 AllowedSameThreadSequenceAndTaskNoThreadTaskRunnerHandle) {
102 ScopedSetSequenceTokenForCurrentThread
103 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
104 ThreadCheckerImpl thread_checker;
105 EXPECT_TRUE(thread_checker.CalledOnValidThread());
106 }
107
TEST(ThreadCheckerTest,DisallowedSameThreadAndSequenceDifferentTasksNoThreadTaskRunnerHandle)108 TEST(ThreadCheckerTest,
109 DisallowedSameThreadAndSequenceDifferentTasksNoThreadTaskRunnerHandle) {
110 std::unique_ptr<ThreadCheckerImpl> thread_checker;
111
112 {
113 ScopedSetSequenceTokenForCurrentThread
114 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
115 thread_checker.reset(new ThreadCheckerImpl);
116 }
117
118 {
119 ScopedSetSequenceTokenForCurrentThread
120 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
121 EXPECT_FALSE(thread_checker->CalledOnValidThread());
122 }
123 }
124
TEST(ThreadCheckerTest,DisallowedDifferentThreadsNoSequenceToken)125 TEST(ThreadCheckerTest, DisallowedDifferentThreadsNoSequenceToken) {
126 ThreadCheckerImpl thread_checker;
127 RunCallbackOnNewThreadSynchronously(
128 Bind(&ExpectNotCalledOnValidThread, Unretained(&thread_checker)));
129 }
130
TEST(ThreadCheckerTest,DisallowedDifferentThreadsSameSequence)131 TEST(ThreadCheckerTest, DisallowedDifferentThreadsSameSequence) {
132 ThreadTaskRunnerHandle thread_task_runner_handle(
133 MakeRefCounted<TestSimpleTaskRunner>());
134 const SequenceToken sequence_token(SequenceToken::Create());
135
136 ScopedSetSequenceTokenForCurrentThread
137 scoped_set_sequence_token_for_current_thread(sequence_token);
138 ThreadCheckerImpl thread_checker;
139 EXPECT_TRUE(thread_checker.CalledOnValidThread());
140
141 RunCallbackOnNewThreadSynchronously(Bind(
142 &ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle,
143 Unretained(&thread_checker), sequence_token));
144 }
145
TEST(ThreadCheckerTest,DisallowedSameThreadDifferentSequence)146 TEST(ThreadCheckerTest, DisallowedSameThreadDifferentSequence) {
147 std::unique_ptr<ThreadCheckerImpl> thread_checker;
148
149 ThreadTaskRunnerHandle thread_task_runner_handle(
150 MakeRefCounted<TestSimpleTaskRunner>());
151
152 {
153 ScopedSetSequenceTokenForCurrentThread
154 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
155 thread_checker.reset(new ThreadCheckerImpl);
156 }
157
158 {
159 // Different SequenceToken.
160 ScopedSetSequenceTokenForCurrentThread
161 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
162 EXPECT_FALSE(thread_checker->CalledOnValidThread());
163 }
164
165 // No SequenceToken.
166 EXPECT_FALSE(thread_checker->CalledOnValidThread());
167 }
168
TEST(ThreadCheckerTest,DetachFromThread)169 TEST(ThreadCheckerTest, DetachFromThread) {
170 ThreadCheckerImpl thread_checker;
171 thread_checker.DetachFromThread();
172
173 // Verify that CalledOnValidThread() returns true when called on a different
174 // thread after a call to DetachFromThread().
175 RunCallbackOnNewThreadSynchronously(
176 Bind(&ExpectCalledOnValidThread, Unretained(&thread_checker)));
177
178 EXPECT_FALSE(thread_checker.CalledOnValidThread());
179 }
180
TEST(ThreadCheckerTest,DetachFromThreadWithSequenceToken)181 TEST(ThreadCheckerTest, DetachFromThreadWithSequenceToken) {
182 ThreadTaskRunnerHandle thread_task_runner_handle(
183 MakeRefCounted<TestSimpleTaskRunner>());
184 ScopedSetSequenceTokenForCurrentThread
185 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
186 ThreadCheckerImpl thread_checker;
187 thread_checker.DetachFromThread();
188
189 // Verify that CalledOnValidThread() returns true when called on a different
190 // thread after a call to DetachFromThread().
191 RunCallbackOnNewThreadSynchronously(
192 Bind(&ExpectCalledOnValidThread, Unretained(&thread_checker)));
193
194 EXPECT_FALSE(thread_checker.CalledOnValidThread());
195 }
196
197 namespace {
198
199 // This fixture is a helper for unit testing the thread checker macros as it is
200 // not possible to inline ExpectDeathOnOtherThread() and
201 // ExpectNoDeathOnOtherThreadAfterDetach() as lambdas since binding
202 // |Unretained(&my_sequence_checker)| wouldn't compile on non-dcheck builds
203 // where it won't be defined.
204 class ThreadCheckerMacroTest : public testing::Test {
205 public:
206 ThreadCheckerMacroTest() = default;
207
ExpectDeathOnOtherThread()208 void ExpectDeathOnOtherThread() {
209 #if DCHECK_IS_ON()
210 EXPECT_DCHECK_DEATH({ DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_); });
211 #else
212 // Happily no-ops on non-dcheck builds.
213 DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_);
214 #endif
215 }
216
ExpectNoDeathOnOtherThreadAfterDetach()217 void ExpectNoDeathOnOtherThreadAfterDetach() {
218 DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_);
219 DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_)
220 << "Make sure it compiles when DCHECK is off";
221 }
222
223 protected:
224 THREAD_CHECKER(my_thread_checker_);
225
226 private:
227 DISALLOW_COPY_AND_ASSIGN(ThreadCheckerMacroTest);
228 };
229
230 } // namespace
231
TEST_F(ThreadCheckerMacroTest,Macros)232 TEST_F(ThreadCheckerMacroTest, Macros) {
233 THREAD_CHECKER(my_thread_checker);
234
235 RunCallbackOnNewThreadSynchronously(Bind(
236 &ThreadCheckerMacroTest::ExpectDeathOnOtherThread, Unretained(this)));
237
238 DETACH_FROM_THREAD(my_thread_checker_);
239
240 RunCallbackOnNewThreadSynchronously(
241 Bind(&ThreadCheckerMacroTest::ExpectNoDeathOnOtherThreadAfterDetach,
242 Unretained(this)));
243 }
244
245 } // namespace base
246