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