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