• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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