xref: /aosp_15_r20/external/cronet/base/threading/thread_checker_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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::internal {
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 
ExpectNotCalledOnValidThreadWithSequenceTokenThreadBound(ThreadCheckerImpl * thread_checker,SequenceToken sequence_token)64 void ExpectNotCalledOnValidThreadWithSequenceTokenThreadBound(
65     ThreadCheckerImpl* thread_checker,
66     SequenceToken sequence_token) {
67   TaskScope task_scope(sequence_token, /* is_thread_bound=*/true);
68   ExpectNotCalledOnValidThread(thread_checker);
69 }
70 
71 }  // namespace
72 
TEST(ThreadCheckerTest,AllowedSameThreadNoSequenceToken)73 TEST(ThreadCheckerTest, AllowedSameThreadNoSequenceToken) {
74   ThreadCheckerImpl thread_checker;
75   EXPECT_TRUE(thread_checker.CalledOnValidThread());
76 }
77 
TEST(ThreadCheckerTest,AllowedSameThreadAndSequenceDifferentThreadBoundTasks)78 TEST(ThreadCheckerTest, AllowedSameThreadAndSequenceDifferentThreadBoundTasks) {
79   std::unique_ptr<ThreadCheckerImpl> thread_checker;
80   const SequenceToken sequence_token = SequenceToken::Create();
81 
82   {
83     TaskScope task_scope(sequence_token,
84                          /* is_thread_bound=*/true);
85     thread_checker = std::make_unique<ThreadCheckerImpl>();
86   }
87 
88   {
89     TaskScope task_scope(sequence_token,
90                          /* is_thread_bound=*/true);
91     EXPECT_TRUE(thread_checker->CalledOnValidThread());
92   }
93 }
94 
TEST(ThreadCheckerTest,AllowedSameThreadSequenceAndTaskNotThreadBound)95 TEST(ThreadCheckerTest, AllowedSameThreadSequenceAndTaskNotThreadBound) {
96   TaskScope task_scope(SequenceToken::Create(),
97                        /* is_thread_bound=*/false);
98   ThreadCheckerImpl thread_checker;
99   EXPECT_TRUE(thread_checker.CalledOnValidThread());
100 }
101 
TEST(ThreadCheckerTest,DisallowedSameThreadAndSequenceDifferentTasksNotThreadBound)102 TEST(ThreadCheckerTest,
103      DisallowedSameThreadAndSequenceDifferentTasksNotThreadBound) {
104   std::unique_ptr<ThreadCheckerImpl> thread_checker;
105 
106   {
107     TaskScope task_scope(SequenceToken::Create(),
108                          /* is_thread_bound=*/false);
109     thread_checker = std::make_unique<ThreadCheckerImpl>();
110   }
111 
112   {
113     TaskScope task_scope(SequenceToken::Create(),
114                          /* is_thread_bound=*/false);
115     EXPECT_FALSE(thread_checker->CalledOnValidThread());
116   }
117 }
118 
TEST(ThreadCheckerTest,DisallowedDifferentThreadsNoSequenceToken)119 TEST(ThreadCheckerTest, DisallowedDifferentThreadsNoSequenceToken) {
120   ThreadCheckerImpl thread_checker;
121   RunCallbackOnNewThreadSynchronously(
122       BindOnce(&ExpectNotCalledOnValidThread, Unretained(&thread_checker)));
123 }
124 
TEST(ThreadCheckerTest,DisallowedDifferentThreadsSameSequence)125 TEST(ThreadCheckerTest, DisallowedDifferentThreadsSameSequence) {
126   SingleThreadTaskRunner::CurrentDefaultHandle
127       single_thread_task_runner_current_default_handle(
128           MakeRefCounted<TestSimpleTaskRunner>());
129   const SequenceToken sequence_token(SequenceToken::Create());
130 
131   TaskScope task_scope(sequence_token,
132                        /* is_thread_bound=*/false);
133   ThreadCheckerImpl thread_checker;
134   EXPECT_TRUE(thread_checker.CalledOnValidThread());
135 
136   RunCallbackOnNewThreadSynchronously(
137       BindOnce(&ExpectNotCalledOnValidThreadWithSequenceTokenThreadBound,
138                Unretained(&thread_checker), sequence_token));
139 }
140 
TEST(ThreadCheckerTest,DisallowedSameThreadDifferentSequence)141 TEST(ThreadCheckerTest, DisallowedSameThreadDifferentSequence) {
142   std::unique_ptr<ThreadCheckerImpl> thread_checker;
143 
144   SingleThreadTaskRunner::CurrentDefaultHandle
145       single_thread_task_runner_current_default_handle(
146           MakeRefCounted<TestSimpleTaskRunner>());
147 
148   {
149     TaskScope task_scope(SequenceToken::Create(),
150                          /* is_thread_bound=*/false);
151     thread_checker = std::make_unique<ThreadCheckerImpl>();
152   }
153 
154   {
155     // Different SequenceToken.
156     TaskScope task_scope(SequenceToken::Create(),
157                          /* is_thread_bound=*/false);
158     EXPECT_FALSE(thread_checker->CalledOnValidThread());
159   }
160 
161   // No SequenceToken.
162   EXPECT_FALSE(thread_checker->CalledOnValidThread());
163 }
164 
TEST(ThreadCheckerTest,DetachFromThread)165 TEST(ThreadCheckerTest, DetachFromThread) {
166   ThreadCheckerImpl thread_checker;
167   thread_checker.DetachFromThread();
168 
169   // Verify that CalledOnValidThread() returns true when called on a different
170   // thread after a call to DetachFromThread().
171   RunCallbackOnNewThreadSynchronously(
172       BindOnce(&ExpectCalledOnValidThread, Unretained(&thread_checker)));
173 
174   EXPECT_FALSE(thread_checker.CalledOnValidThread());
175 }
176 
TEST(ThreadCheckerTest,DetachFromThreadWithSequenceToken)177 TEST(ThreadCheckerTest, DetachFromThreadWithSequenceToken) {
178   SingleThreadTaskRunner::CurrentDefaultHandle
179       single_thread_task_runner_current_default_handle(
180           MakeRefCounted<TestSimpleTaskRunner>());
181   TaskScope task_scope(SequenceToken::Create(),
182                        /* is_thread_bound=*/false);
183   ThreadCheckerImpl thread_checker;
184   thread_checker.DetachFromThread();
185 
186   // Verify that CalledOnValidThread() returns true when called on a different
187   // thread after a call to DetachFromThread().
188   RunCallbackOnNewThreadSynchronously(
189       BindOnce(&ExpectCalledOnValidThread, Unretained(&thread_checker)));
190 
191   EXPECT_FALSE(thread_checker.CalledOnValidThread());
192 }
193 
194 // Owns a ThreadCheckerImpl and asserts that CalledOnValidThread() is valid
195 // in ~ThreadCheckerOwner.
196 class ThreadCheckerOwner {
197  public:
ThreadCheckerOwner(bool detach_from_thread)198   explicit ThreadCheckerOwner(bool detach_from_thread) {
199     if (detach_from_thread)
200       checker_.DetachFromThread();
201   }
202 
203   ThreadCheckerOwner(const ThreadCheckerOwner&) = delete;
204   ThreadCheckerOwner& operator=(const ThreadCheckerOwner&) = delete;
205 
~ThreadCheckerOwner()206   ~ThreadCheckerOwner() { EXPECT_TRUE(checker_.CalledOnValidThread()); }
207 
208  private:
209   ThreadCheckerImpl checker_;
210 };
211 
212 // Verifies ThreadCheckerImpl::CalledOnValidThread() returns true if called
213 // during thread destruction.
TEST(ThreadCheckerTest,CalledOnValidThreadFromThreadDestruction)214 TEST(ThreadCheckerTest, CalledOnValidThreadFromThreadDestruction) {
215   ThreadLocalOwnedPointer<ThreadCheckerOwner> thread_local_owner;
216   RunCallbackOnNewThreadSynchronously(BindLambdaForTesting([&]() {
217     thread_local_owner.Set(std::make_unique<ThreadCheckerOwner>(false));
218   }));
219 }
220 
221 // Variant of CalledOnValidThreadFromThreadDestruction that calls
222 // ThreadCheckerImpl::DetachFromThread().
TEST(ThreadCheckerTest,CalledOnValidThreadFromThreadDestructionDetached)223 TEST(ThreadCheckerTest, CalledOnValidThreadFromThreadDestructionDetached) {
224   ThreadLocalOwnedPointer<ThreadCheckerOwner> thread_local_owner;
225   RunCallbackOnNewThreadSynchronously(BindLambdaForTesting([&]() {
226     thread_local_owner.Set(std::make_unique<ThreadCheckerOwner>(true));
227   }));
228 }
229 
TEST(ThreadCheckerTest,Move)230 TEST(ThreadCheckerTest, Move) {
231   ThreadCheckerImpl initial;
232   EXPECT_TRUE(initial.CalledOnValidThread());
233 
234   ThreadCheckerImpl move_constructed(std::move(initial));
235   EXPECT_TRUE(move_constructed.CalledOnValidThread());
236 
237   ThreadCheckerImpl move_assigned;
238   move_assigned = std::move(move_constructed);
239   EXPECT_TRUE(move_assigned.CalledOnValidThread());
240 
241   // The two ThreadCheckerImpls moved from should be able to rebind to another
242   // thread.
243   RunCallbackOnNewThreadSynchronously(
244       BindOnce(&ExpectCalledOnValidThread, Unretained(&initial)));
245   RunCallbackOnNewThreadSynchronously(
246       BindOnce(&ExpectCalledOnValidThread, Unretained(&move_constructed)));
247 
248   // But the latest one shouldn't be able to run on another thread.
249   RunCallbackOnNewThreadSynchronously(
250       BindOnce(&ExpectNotCalledOnValidThread, Unretained(&move_assigned)));
251 
252   EXPECT_TRUE(move_assigned.CalledOnValidThread());
253 }
254 
TEST(ThreadCheckerTest,MoveAssignIntoDetached)255 TEST(ThreadCheckerTest, MoveAssignIntoDetached) {
256   ThreadCheckerImpl initial;
257 
258   ThreadCheckerImpl move_assigned;
259   move_assigned.DetachFromThread();
260   move_assigned = std::move(initial);
261 
262   // |initial| is detached after move.
263   RunCallbackOnNewThreadSynchronously(
264       BindOnce(&ExpectCalledOnValidThread, Unretained(&initial)));
265 
266   // |move_assigned| should be associated with the main thread.
267   RunCallbackOnNewThreadSynchronously(
268       BindOnce(&ExpectNotCalledOnValidThread, Unretained(&move_assigned)));
269 
270   EXPECT_TRUE(move_assigned.CalledOnValidThread());
271 }
272 
TEST(ThreadCheckerTest,MoveFromDetachedRebinds)273 TEST(ThreadCheckerTest, MoveFromDetachedRebinds) {
274   ThreadCheckerImpl initial;
275   initial.DetachFromThread();
276 
277   ThreadCheckerImpl moved_into(std::move(initial));
278 
279   // |initial| is still detached after move.
280   RunCallbackOnNewThreadSynchronously(
281       BindOnce(&ExpectCalledOnValidThread, Unretained(&initial)));
282 
283   // |moved_into| is bound to the current thread as part of the move.
284   RunCallbackOnNewThreadSynchronously(
285       BindOnce(&ExpectNotCalledOnValidThread, Unretained(&moved_into)));
286   EXPECT_TRUE(moved_into.CalledOnValidThread());
287 }
288 
TEST(ThreadCheckerTest,MoveOffThreadBanned)289 TEST(ThreadCheckerTest, MoveOffThreadBanned) {
290   GTEST_FLAG_SET(death_test_style, "threadsafe");
291 
292   ThreadCheckerImpl other_thread;
293   other_thread.DetachFromThread();
294   RunCallbackOnNewThreadSynchronously(
295       BindOnce(&ExpectCalledOnValidThread, Unretained(&other_thread)));
296 
297   EXPECT_DCHECK_DEATH(ThreadCheckerImpl main_thread(std::move(other_thread)));
298 }
299 
300 namespace {
301 
302 // This fixture is a helper for unit testing the thread checker macros as it is
303 // not possible to inline ExpectDeathOnOtherThread() and
304 // ExpectNoDeathOnOtherThreadAfterDetach() as lambdas since binding
305 // |Unretained(&my_sequence_checker)| wouldn't compile on non-dcheck builds
306 // where it won't be defined.
307 class ThreadCheckerMacroTest : public testing::Test {
308  public:
309   ThreadCheckerMacroTest() = default;
310 
311   ThreadCheckerMacroTest(const ThreadCheckerMacroTest&) = delete;
312   ThreadCheckerMacroTest& operator=(const ThreadCheckerMacroTest&) = delete;
313 
ExpectDeathOnOtherThread()314   void ExpectDeathOnOtherThread() {
315 #if DCHECK_IS_ON()
316     EXPECT_DCHECK_DEATH({ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); });
317 #else
318     // Happily no-ops on non-dcheck builds.
319     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
320 #endif
321   }
322 
ExpectNoDeathOnOtherThreadAfterDetach()323   void ExpectNoDeathOnOtherThreadAfterDetach() {
324     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
325   }
326 
327  protected:
328   THREAD_CHECKER(thread_checker_);
329 };
330 
331 }  // namespace
332 
TEST_F(ThreadCheckerMacroTest,Macros)333 TEST_F(ThreadCheckerMacroTest, Macros) {
334   GTEST_FLAG_SET(death_test_style, "threadsafe");
335 
336   THREAD_CHECKER(my_thread_checker);
337 
338   RunCallbackOnNewThreadSynchronously(BindOnce(
339       &ThreadCheckerMacroTest::ExpectDeathOnOtherThread, Unretained(this)));
340 
341   DETACH_FROM_THREAD(thread_checker_);
342 
343   RunCallbackOnNewThreadSynchronously(
344       BindOnce(&ThreadCheckerMacroTest::ExpectNoDeathOnOtherThreadAfterDetach,
345                Unretained(this)));
346 }
347 
348 }  // namespace base::internal
349