• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/sequence_checker.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <string>
11 #include <utility>
12 
13 #include "base/functional/bind.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/sequence_token.h"
16 #include "base/task/single_thread_task_runner.h"
17 #include "base/task/thread_pool.h"
18 #include "base/test/bind.h"
19 #include "base/test/gtest_util.h"
20 #include "base/test/task_environment.h"
21 #include "base/threading/simple_thread.h"
22 #include "base/threading/thread_local.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 namespace base {
26 
27 namespace {
28 
29 // Runs a callback on another thread.
30 class RunCallbackThread : public SimpleThread {
31  public:
RunCallbackThread(OnceClosure callback)32   explicit RunCallbackThread(OnceClosure callback)
33       : SimpleThread("RunCallbackThread"), callback_(std::move(callback)) {
34     Start();
35     Join();
36   }
37   RunCallbackThread(const RunCallbackThread&) = delete;
38   RunCallbackThread& operator=(const RunCallbackThread&) = delete;
39 
40  private:
41   // SimpleThread:
Run()42   void Run() override { std::move(callback_).Run(); }
43 
44   OnceClosure callback_;
45 };
46 
ExpectCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)47 void ExpectCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
48   ASSERT_TRUE(sequence_checker);
49 
50   // This should bind |sequence_checker| to the current sequence if it wasn't
51   // already bound to a sequence.
52   EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
53 
54   // Since |sequence_checker| is now bound to the current sequence, another call
55   // to CalledOnValidSequence() should return true.
56   EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
57 }
58 
ExpectCalledOnValidSequenceWithSequenceToken(SequenceCheckerImpl * sequence_checker,SequenceToken sequence_token)59 void ExpectCalledOnValidSequenceWithSequenceToken(
60     SequenceCheckerImpl* sequence_checker,
61     SequenceToken sequence_token) {
62   ScopedSetSequenceTokenForCurrentThread
63       scoped_set_sequence_token_for_current_thread(sequence_token);
64   ExpectCalledOnValidSequence(sequence_checker);
65 }
66 
ExpectNotCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)67 void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
68   ASSERT_TRUE(sequence_checker);
69   EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
70 }
71 
72 }  // namespace
73 
TEST(SequenceCheckerTest,CallsAllowedOnSameThreadNoSequenceToken)74 TEST(SequenceCheckerTest, CallsAllowedOnSameThreadNoSequenceToken) {
75   SequenceCheckerImpl sequence_checker;
76   EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
77 }
78 
TEST(SequenceCheckerTest,CallsAllowedOnSameThreadSameSequenceToken)79 TEST(SequenceCheckerTest, CallsAllowedOnSameThreadSameSequenceToken) {
80   ScopedSetSequenceTokenForCurrentThread
81       scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
82   SequenceCheckerImpl sequence_checker;
83   EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
84 }
85 
TEST(SequenceCheckerTest,CallsDisallowedOnDifferentThreadsNoSequenceToken)86 TEST(SequenceCheckerTest, CallsDisallowedOnDifferentThreadsNoSequenceToken) {
87   SequenceCheckerImpl sequence_checker;
88   RunCallbackThread thread(
89       BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker)));
90 }
91 
TEST(SequenceCheckerTest,CallsAllowedOnDifferentThreadsSameSequenceToken)92 TEST(SequenceCheckerTest, CallsAllowedOnDifferentThreadsSameSequenceToken) {
93   const SequenceToken sequence_token(SequenceToken::Create());
94 
95   ScopedSetSequenceTokenForCurrentThread
96       scoped_set_sequence_token_for_current_thread(sequence_token);
97   SequenceCheckerImpl sequence_checker;
98   EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
99 
100   RunCallbackThread thread(
101       BindOnce(&ExpectCalledOnValidSequenceWithSequenceToken,
102                Unretained(&sequence_checker), sequence_token));
103 }
104 
TEST(SequenceCheckerTest,CallsDisallowedOnSameThreadDifferentSequenceToken)105 TEST(SequenceCheckerTest, CallsDisallowedOnSameThreadDifferentSequenceToken) {
106   std::unique_ptr<SequenceCheckerImpl> sequence_checker;
107 
108   {
109     ScopedSetSequenceTokenForCurrentThread
110         scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
111     sequence_checker = std::make_unique<SequenceCheckerImpl>();
112   }
113 
114   {
115     // Different SequenceToken.
116     ScopedSetSequenceTokenForCurrentThread
117         scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
118     EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
119   }
120 
121   // No SequenceToken.
122   EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
123 }
124 
TEST(SequenceCheckerTest,DetachFromSequence)125 TEST(SequenceCheckerTest, DetachFromSequence) {
126   std::unique_ptr<SequenceCheckerImpl> sequence_checker;
127 
128   {
129     ScopedSetSequenceTokenForCurrentThread
130         scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
131     sequence_checker = std::make_unique<SequenceCheckerImpl>();
132   }
133 
134   sequence_checker->DetachFromSequence();
135 
136   {
137     // Verify that CalledOnValidSequence() returns true when called with
138     // a different sequence token after a call to DetachFromSequence().
139     ScopedSetSequenceTokenForCurrentThread
140         scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
141     EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
142   }
143 }
144 
TEST(SequenceCheckerTest,DetachFromSequenceNoSequenceToken)145 TEST(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) {
146   SequenceCheckerImpl sequence_checker;
147   sequence_checker.DetachFromSequence();
148 
149   // Verify that CalledOnValidSequence() returns true when called on a
150   // different thread after a call to DetachFromSequence().
151   RunCallbackThread thread(
152       BindOnce(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)));
153 
154   EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
155 }
156 
TEST(SequenceCheckerTest,Move)157 TEST(SequenceCheckerTest, Move) {
158   SequenceCheckerImpl initial;
159   EXPECT_TRUE(initial.CalledOnValidSequence());
160 
161   SequenceCheckerImpl move_constructed(std::move(initial));
162   EXPECT_TRUE(move_constructed.CalledOnValidSequence());
163 
164   SequenceCheckerImpl move_assigned;
165   move_assigned = std::move(move_constructed);
166 
167   // The two SequenceCheckerImpls moved from should be able to rebind to another
168   // sequence.
169   RunCallbackThread thread1(
170       BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
171   RunCallbackThread thread2(
172       BindOnce(&ExpectCalledOnValidSequence, Unretained(&move_constructed)));
173 
174   // But the latest one shouldn't be able to run on another sequence.
175   RunCallbackThread thread(
176       BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
177 
178   EXPECT_TRUE(move_assigned.CalledOnValidSequence());
179 }
180 
TEST(SequenceCheckerTest,MoveAssignIntoDetached)181 TEST(SequenceCheckerTest, MoveAssignIntoDetached) {
182   SequenceCheckerImpl initial;
183 
184   SequenceCheckerImpl move_assigned;
185   move_assigned.DetachFromSequence();
186   move_assigned = std::move(initial);
187 
188   // |initial| is detached after move.
189   RunCallbackThread thread1(
190       BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
191 
192   // |move_assigned| should be associated with the main thread.
193   RunCallbackThread thread2(
194       BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
195 
196   EXPECT_TRUE(move_assigned.CalledOnValidSequence());
197 }
198 
TEST(SequenceCheckerTest,MoveFromDetachedRebinds)199 TEST(SequenceCheckerTest, MoveFromDetachedRebinds) {
200   SequenceCheckerImpl initial;
201   initial.DetachFromSequence();
202 
203   SequenceCheckerImpl moved_into(std::move(initial));
204 
205   // |initial| is still detached after move.
206   RunCallbackThread thread1(
207       BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
208 
209   // |moved_into| is bound to the current sequence as part of the move.
210   RunCallbackThread thread2(
211       BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&moved_into)));
212   EXPECT_TRUE(moved_into.CalledOnValidSequence());
213 }
214 
TEST(SequenceCheckerTest,MoveOffSequenceBanned)215 TEST(SequenceCheckerTest, MoveOffSequenceBanned) {
216   testing::GTEST_FLAG(death_test_style) = "threadsafe";
217 
218   SequenceCheckerImpl other_sequence;
219   other_sequence.DetachFromSequence();
220   RunCallbackThread thread(
221       BindOnce(&ExpectCalledOnValidSequence, Unretained(&other_sequence)));
222 
223   EXPECT_DCHECK_DEATH(
224       SequenceCheckerImpl main_sequence(std::move(other_sequence)));
225 }
226 
TEST(SequenceCheckerMacroTest,Macros)227 TEST(SequenceCheckerMacroTest, Macros) {
228   auto scope = std::make_unique<ScopedSetSequenceTokenForCurrentThread>(
229       SequenceToken::Create());
230   SEQUENCE_CHECKER(my_sequence_checker);
231 
232   {
233     // Don't expect a DCHECK death when a SequenceChecker is used on the right
234     // sequence.
235     DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
236   }
237   scope.reset();
238 
239 #if DCHECK_IS_ON()
240   // Expect DCHECK death when used on a different sequence.
241   EXPECT_DCHECK_DEATH(
242       { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker); });
243 #else
244     // Happily no-ops on non-dcheck builds.
245   DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
246 #endif
247 
248   DETACH_FROM_SEQUENCE(my_sequence_checker);
249 
250   // Don't expect a DCHECK death when a SequenceChecker is used for the first
251   // time after having been detached.
252   DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
253 }
254 
255 // Owns a SequenceCheckerImpl, and asserts that CalledOnValidSequence() is valid
256 // in ~SequenceCheckerOwner.
257 class SequenceCheckerOwner {
258  public:
259   SequenceCheckerOwner() = default;
260   SequenceCheckerOwner(const SequenceCheckerOwner&) = delete;
261   SequenceCheckerOwner& operator=(const SequenceCheckerOwner&) = delete;
~SequenceCheckerOwner()262   ~SequenceCheckerOwner() { EXPECT_TRUE(checker_.CalledOnValidSequence()); }
263 
264  private:
265   SequenceCheckerImpl checker_;
266 };
267 
268 // Verifies SequenceCheckerImpl::CalledOnValidSequence() returns true if called
269 // during thread destruction.
TEST(SequenceCheckerTest,CalledOnValidSequenceFromThreadDestruction)270 TEST(SequenceCheckerTest, CalledOnValidSequenceFromThreadDestruction) {
271   SequenceChecker::EnableStackLogging();
272   ThreadLocalOwnedPointer<SequenceCheckerOwner> thread_local_owner;
273   {
274     test::TaskEnvironment task_environment;
275     auto task_runner = ThreadPool::CreateSequencedTaskRunner({});
276     task_runner->PostTask(
277         FROM_HERE, BindLambdaForTesting([&]() {
278           thread_local_owner.Set(std::make_unique<SequenceCheckerOwner>());
279         }));
280     task_runner = nullptr;
281     task_environment.RunUntilIdle();
282   }
283 }
284 
285 }  // namespace base
286