1 // Copyright 2012 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/threading/thread_checker.h"
6
7 #include <memory>
8
9 #include "base/functional/bind.h"
10 #include "base/functional/callback_helpers.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/sequence_token.h"
13 #include "base/task/single_thread_task_runner.h"
14 #include "base/test/bind.h"
15 #include "base/test/gtest_util.h"
16 #include "base/test/test_simple_task_runner.h"
17 #include "base/threading/simple_thread.h"
18 #include "base/threading/thread_local.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace base {
22 namespace {
23
24 // A thread that runs a callback.
25 class RunCallbackThread : public SimpleThread {
26 public:
RunCallbackThread(OnceClosure callback)27 explicit RunCallbackThread(OnceClosure callback)
28 : SimpleThread("RunCallbackThread"), callback_(std::move(callback)) {}
29
30 RunCallbackThread(const RunCallbackThread&) = delete;
31 RunCallbackThread& operator=(const RunCallbackThread&) = delete;
32
33 private:
34 // SimpleThread:
Run()35 void Run() override { std::move(callback_).Run(); }
36
37 OnceClosure callback_;
38 };
39
40 // Runs a callback on a new thread synchronously.
RunCallbackOnNewThreadSynchronously(OnceClosure callback)41 void RunCallbackOnNewThreadSynchronously(OnceClosure callback) {
42 RunCallbackThread run_callback_thread(std::move(callback));
43 run_callback_thread.Start();
44 run_callback_thread.Join();
45 }
46
ExpectCalledOnValidThread(ThreadCheckerImpl * thread_checker)47 void ExpectCalledOnValidThread(ThreadCheckerImpl* thread_checker) {
48 ASSERT_TRUE(thread_checker);
49
50 // This should bind |thread_checker| to the current thread if it wasn't
51 // already bound to a thread.
52 EXPECT_TRUE(thread_checker->CalledOnValidThread());
53
54 // Since |thread_checker| is now bound to the current thread, another call to
55 // CalledOnValidThread() should return true.
56 EXPECT_TRUE(thread_checker->CalledOnValidThread());
57 }
58
ExpectNotCalledOnValidThread(ThreadCheckerImpl * thread_checker)59 void ExpectNotCalledOnValidThread(ThreadCheckerImpl* thread_checker) {
60 ASSERT_TRUE(thread_checker);
61 EXPECT_FALSE(thread_checker->CalledOnValidThread());
62 }
63
ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle(ThreadCheckerImpl * thread_checker,SequenceToken sequence_token)64 void ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle(
65 ThreadCheckerImpl* thread_checker,
66 SequenceToken sequence_token) {
67 SingleThreadTaskRunner::CurrentDefaultHandle
68 single_thread_task_runner_current_default_handle(
69 MakeRefCounted<TestSimpleTaskRunner>());
70 ScopedSetSequenceTokenForCurrentThread
71 scoped_set_sequence_token_for_current_thread(sequence_token);
72 ExpectNotCalledOnValidThread(thread_checker);
73 }
74
75 } // namespace
76
TEST(ThreadCheckerTest,AllowedSameThreadNoSequenceToken)77 TEST(ThreadCheckerTest, AllowedSameThreadNoSequenceToken) {
78 ThreadCheckerImpl thread_checker;
79 EXPECT_TRUE(thread_checker.CalledOnValidThread());
80 }
81
TEST(ThreadCheckerTest,AllowedSameThreadAndSequenceDifferentTasksWithThreadTaskRunnerHandle)82 TEST(ThreadCheckerTest,
83 AllowedSameThreadAndSequenceDifferentTasksWithThreadTaskRunnerHandle) {
84 SingleThreadTaskRunner::CurrentDefaultHandle
85 single_thread_task_runner_current_default_handle(
86 MakeRefCounted<TestSimpleTaskRunner>());
87
88 std::unique_ptr<ThreadCheckerImpl> thread_checker;
89 const SequenceToken sequence_token = SequenceToken::Create();
90
91 {
92 ScopedSetSequenceTokenForCurrentThread
93 scoped_set_sequence_token_for_current_thread(sequence_token);
94 thread_checker = std::make_unique<ThreadCheckerImpl>();
95 }
96
97 {
98 ScopedSetSequenceTokenForCurrentThread
99 scoped_set_sequence_token_for_current_thread(sequence_token);
100 EXPECT_TRUE(thread_checker->CalledOnValidThread());
101 }
102 }
103
TEST(ThreadCheckerTest,AllowedSameThreadSequenceAndTaskNoThreadTaskRunnerHandle)104 TEST(ThreadCheckerTest,
105 AllowedSameThreadSequenceAndTaskNoThreadTaskRunnerHandle) {
106 ScopedSetSequenceTokenForCurrentThread
107 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
108 ThreadCheckerImpl thread_checker;
109 EXPECT_TRUE(thread_checker.CalledOnValidThread());
110 }
111
TEST(ThreadCheckerTest,DisallowedSameThreadAndSequenceDifferentTasksNoThreadTaskRunnerHandle)112 TEST(ThreadCheckerTest,
113 DisallowedSameThreadAndSequenceDifferentTasksNoThreadTaskRunnerHandle) {
114 std::unique_ptr<ThreadCheckerImpl> thread_checker;
115
116 {
117 ScopedSetSequenceTokenForCurrentThread
118 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
119 thread_checker = std::make_unique<ThreadCheckerImpl>();
120 }
121
122 {
123 ScopedSetSequenceTokenForCurrentThread
124 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
125 EXPECT_FALSE(thread_checker->CalledOnValidThread());
126 }
127 }
128
TEST(ThreadCheckerTest,DisallowedDifferentThreadsNoSequenceToken)129 TEST(ThreadCheckerTest, DisallowedDifferentThreadsNoSequenceToken) {
130 ThreadCheckerImpl thread_checker;
131 RunCallbackOnNewThreadSynchronously(
132 BindOnce(&ExpectNotCalledOnValidThread, Unretained(&thread_checker)));
133 }
134
TEST(ThreadCheckerTest,DisallowedDifferentThreadsSameSequence)135 TEST(ThreadCheckerTest, DisallowedDifferentThreadsSameSequence) {
136 SingleThreadTaskRunner::CurrentDefaultHandle
137 single_thread_task_runner_current_default_handle(
138 MakeRefCounted<TestSimpleTaskRunner>());
139 const SequenceToken sequence_token(SequenceToken::Create());
140
141 ScopedSetSequenceTokenForCurrentThread
142 scoped_set_sequence_token_for_current_thread(sequence_token);
143 ThreadCheckerImpl thread_checker;
144 EXPECT_TRUE(thread_checker.CalledOnValidThread());
145
146 RunCallbackOnNewThreadSynchronously(BindOnce(
147 &ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle,
148 Unretained(&thread_checker), sequence_token));
149 }
150
TEST(ThreadCheckerTest,DisallowedSameThreadDifferentSequence)151 TEST(ThreadCheckerTest, DisallowedSameThreadDifferentSequence) {
152 std::unique_ptr<ThreadCheckerImpl> thread_checker;
153
154 SingleThreadTaskRunner::CurrentDefaultHandle
155 single_thread_task_runner_current_default_handle(
156 MakeRefCounted<TestSimpleTaskRunner>());
157
158 {
159 ScopedSetSequenceTokenForCurrentThread
160 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
161 thread_checker = std::make_unique<ThreadCheckerImpl>();
162 }
163
164 {
165 // Different SequenceToken.
166 ScopedSetSequenceTokenForCurrentThread
167 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
168 EXPECT_FALSE(thread_checker->CalledOnValidThread());
169 }
170
171 // No SequenceToken.
172 EXPECT_FALSE(thread_checker->CalledOnValidThread());
173 }
174
TEST(ThreadCheckerTest,DetachFromThread)175 TEST(ThreadCheckerTest, DetachFromThread) {
176 ThreadCheckerImpl thread_checker;
177 thread_checker.DetachFromThread();
178
179 // Verify that CalledOnValidThread() returns true when called on a different
180 // thread after a call to DetachFromThread().
181 RunCallbackOnNewThreadSynchronously(
182 BindOnce(&ExpectCalledOnValidThread, Unretained(&thread_checker)));
183
184 EXPECT_FALSE(thread_checker.CalledOnValidThread());
185 }
186
TEST(ThreadCheckerTest,DetachFromThreadWithSequenceToken)187 TEST(ThreadCheckerTest, DetachFromThreadWithSequenceToken) {
188 SingleThreadTaskRunner::CurrentDefaultHandle
189 single_thread_task_runner_current_default_handle(
190 MakeRefCounted<TestSimpleTaskRunner>());
191 ScopedSetSequenceTokenForCurrentThread
192 scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
193 ThreadCheckerImpl thread_checker;
194 thread_checker.DetachFromThread();
195
196 // Verify that CalledOnValidThread() returns true when called on a different
197 // thread after a call to DetachFromThread().
198 RunCallbackOnNewThreadSynchronously(
199 BindOnce(&ExpectCalledOnValidThread, Unretained(&thread_checker)));
200
201 EXPECT_FALSE(thread_checker.CalledOnValidThread());
202 }
203
204 // Owns a ThreadCheckerImpl and asserts that CalledOnValidThread() is valid
205 // in ~ThreadCheckerOwner.
206 class ThreadCheckerOwner {
207 public:
ThreadCheckerOwner(bool detach_from_thread)208 explicit ThreadCheckerOwner(bool detach_from_thread) {
209 if (detach_from_thread)
210 checker_.DetachFromThread();
211 }
212
213 ThreadCheckerOwner(const ThreadCheckerOwner&) = delete;
214 ThreadCheckerOwner& operator=(const ThreadCheckerOwner&) = delete;
215
~ThreadCheckerOwner()216 ~ThreadCheckerOwner() { EXPECT_TRUE(checker_.CalledOnValidThread()); }
217
218 private:
219 ThreadCheckerImpl checker_;
220 };
221
222 // Verifies ThreadCheckerImpl::CalledOnValidThread() returns true if called
223 // during thread destruction.
TEST(ThreadCheckerTest,CalledOnValidThreadFromThreadDestruction)224 TEST(ThreadCheckerTest, CalledOnValidThreadFromThreadDestruction) {
225 ThreadLocalOwnedPointer<ThreadCheckerOwner> thread_local_owner;
226 RunCallbackOnNewThreadSynchronously(BindLambdaForTesting([&]() {
227 thread_local_owner.Set(std::make_unique<ThreadCheckerOwner>(false));
228 }));
229 }
230
231 // Variant of CalledOnValidThreadFromThreadDestruction that calls
232 // ThreadCheckerImpl::DetachFromThread().
TEST(ThreadCheckerTest,CalledOnValidThreadFromThreadDestructionDetached)233 TEST(ThreadCheckerTest, CalledOnValidThreadFromThreadDestructionDetached) {
234 ThreadLocalOwnedPointer<ThreadCheckerOwner> thread_local_owner;
235 RunCallbackOnNewThreadSynchronously(BindLambdaForTesting([&]() {
236 thread_local_owner.Set(std::make_unique<ThreadCheckerOwner>(true));
237 }));
238 }
239
TEST(ThreadCheckerTest,Move)240 TEST(ThreadCheckerTest, Move) {
241 ThreadCheckerImpl initial;
242 EXPECT_TRUE(initial.CalledOnValidThread());
243
244 ThreadCheckerImpl move_constructed(std::move(initial));
245 EXPECT_TRUE(move_constructed.CalledOnValidThread());
246
247 ThreadCheckerImpl move_assigned;
248 move_assigned = std::move(move_constructed);
249 EXPECT_TRUE(move_assigned.CalledOnValidThread());
250
251 // The two ThreadCheckerImpls moved from should be able to rebind to another
252 // thread.
253 RunCallbackOnNewThreadSynchronously(
254 BindOnce(&ExpectCalledOnValidThread, Unretained(&initial)));
255 RunCallbackOnNewThreadSynchronously(
256 BindOnce(&ExpectCalledOnValidThread, Unretained(&move_constructed)));
257
258 // But the latest one shouldn't be able to run on another thread.
259 RunCallbackOnNewThreadSynchronously(
260 BindOnce(&ExpectNotCalledOnValidThread, Unretained(&move_assigned)));
261
262 EXPECT_TRUE(move_assigned.CalledOnValidThread());
263 }
264
TEST(ThreadCheckerTest,MoveAssignIntoDetached)265 TEST(ThreadCheckerTest, MoveAssignIntoDetached) {
266 ThreadCheckerImpl initial;
267
268 ThreadCheckerImpl move_assigned;
269 move_assigned.DetachFromThread();
270 move_assigned = std::move(initial);
271
272 // |initial| is detached after move.
273 RunCallbackOnNewThreadSynchronously(
274 BindOnce(&ExpectCalledOnValidThread, Unretained(&initial)));
275
276 // |move_assigned| should be associated with the main thread.
277 RunCallbackOnNewThreadSynchronously(
278 BindOnce(&ExpectNotCalledOnValidThread, Unretained(&move_assigned)));
279
280 EXPECT_TRUE(move_assigned.CalledOnValidThread());
281 }
282
TEST(ThreadCheckerTest,MoveFromDetachedRebinds)283 TEST(ThreadCheckerTest, MoveFromDetachedRebinds) {
284 ThreadCheckerImpl initial;
285 initial.DetachFromThread();
286
287 ThreadCheckerImpl moved_into(std::move(initial));
288
289 // |initial| is still detached after move.
290 RunCallbackOnNewThreadSynchronously(
291 BindOnce(&ExpectCalledOnValidThread, Unretained(&initial)));
292
293 // |moved_into| is bound to the current thread as part of the move.
294 RunCallbackOnNewThreadSynchronously(
295 BindOnce(&ExpectNotCalledOnValidThread, Unretained(&moved_into)));
296 EXPECT_TRUE(moved_into.CalledOnValidThread());
297 }
298
TEST(ThreadCheckerTest,MoveOffThreadBanned)299 TEST(ThreadCheckerTest, MoveOffThreadBanned) {
300 testing::GTEST_FLAG(death_test_style) = "threadsafe";
301
302 ThreadCheckerImpl other_thread;
303 other_thread.DetachFromThread();
304 RunCallbackOnNewThreadSynchronously(
305 BindOnce(&ExpectCalledOnValidThread, Unretained(&other_thread)));
306
307 EXPECT_DCHECK_DEATH(ThreadCheckerImpl main_thread(std::move(other_thread)));
308 }
309
310 namespace {
311
312 // This fixture is a helper for unit testing the thread checker macros as it is
313 // not possible to inline ExpectDeathOnOtherThread() and
314 // ExpectNoDeathOnOtherThreadAfterDetach() as lambdas since binding
315 // |Unretained(&my_sequence_checker)| wouldn't compile on non-dcheck builds
316 // where it won't be defined.
317 class ThreadCheckerMacroTest : public testing::Test {
318 public:
319 ThreadCheckerMacroTest() = default;
320
321 ThreadCheckerMacroTest(const ThreadCheckerMacroTest&) = delete;
322 ThreadCheckerMacroTest& operator=(const ThreadCheckerMacroTest&) = delete;
323
ExpectDeathOnOtherThread()324 void ExpectDeathOnOtherThread() {
325 #if DCHECK_IS_ON()
326 EXPECT_DCHECK_DEATH({ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); });
327 #else
328 // Happily no-ops on non-dcheck builds.
329 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
330 #endif
331 }
332
ExpectNoDeathOnOtherThreadAfterDetach()333 void ExpectNoDeathOnOtherThreadAfterDetach() {
334 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
335 }
336
337 protected:
338 THREAD_CHECKER(thread_checker_);
339 };
340
341 } // namespace
342
TEST_F(ThreadCheckerMacroTest,Macros)343 TEST_F(ThreadCheckerMacroTest, Macros) {
344 testing::GTEST_FLAG(death_test_style) = "threadsafe";
345
346 THREAD_CHECKER(my_thread_checker);
347
348 RunCallbackOnNewThreadSynchronously(BindOnce(
349 &ThreadCheckerMacroTest::ExpectDeathOnOtherThread, Unretained(this)));
350
351 DETACH_FROM_THREAD(thread_checker_);
352
353 RunCallbackOnNewThreadSynchronously(
354 BindOnce(&ThreadCheckerMacroTest::ExpectNoDeathOnOtherThreadAfterDetach,
355 Unretained(this)));
356 }
357
358 } // namespace base
359