[go: nahoru, domu]

blob: 4ee9b135448d056f133176c31da9669d4d3170a7 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2013 The Chromium Authors
akalin@chromium.org399ed422012-12-27 19:58:002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
gabd52c912a2017-05-11 04:15:595#include "base/sequence_checker.h"
6
avi9b6f42932015-12-26 22:15:147#include <stddef.h>
8
dcheng093de9b2016-04-04 21:25:519#include <memory>
fdorayeed5fa72016-07-26 22:28:4510#include <string>
David Bienvenu5f4d4f02020-09-27 16:55:0311#include <utility>
danakj0c8d4aa2015-11-25 05:29:5812
Avi Drissman63e1f992023-01-13 18:54:4313#include "base/functional/bind.h"
14#include "base/functional/callback_helpers.h"
François Doray311bf142024-01-17 19:59:3015#include "base/sequence_checker_impl.h"
fdorayeed5fa72016-07-26 22:28:4516#include "base/sequence_token.h"
Patrick Monette643cdf62021-10-15 19:13:4217#include "base/task/single_thread_task_runner.h"
Gabriel Charette0bcc6ca2020-03-14 00:12:4418#include "base/task/thread_pool.h"
Guido Urdanetaef4e91942020-11-09 15:06:2419#include "base/test/bind.h"
gabd52c912a2017-05-11 04:15:5920#include "base/test/gtest_util.h"
Gabriel Charettec7108742019-08-23 03:31:4021#include "base/test/task_environment.h"
fdorayeed5fa72016-07-26 22:28:4522#include "base/threading/simple_thread.h"
Scott Violet909058d2019-07-29 23:07:4223#include "base/threading/thread_local.h"
dewittj@chromium.org8e765972013-07-26 17:10:0224#include "testing/gtest/include/gtest/gtest.h"
tommycli@chromium.org5c0b4432013-07-26 14:23:5625
François Doray524d2a22024-01-04 09:54:1626namespace base::internal {
akalin@chromium.org399ed422012-12-27 19:58:0027
28namespace {
29
fdorayeed5fa72016-07-26 22:28:4530// Runs a callback on another thread.
31class RunCallbackThread : public SimpleThread {
tommycli@chromium.orgd52426c2013-07-30 19:26:4032 public:
kylechar01598d72019-05-21 18:35:3133 explicit RunCallbackThread(OnceClosure callback)
34 : SimpleThread("RunCallbackThread"), callback_(std::move(callback)) {
fdorayeed5fa72016-07-26 22:28:4535 Start();
36 Join();
tommycli@chromium.orgd52426c2013-07-30 19:26:4037 }
David Bienvenu5f4d4f02020-09-27 16:55:0338 RunCallbackThread(const RunCallbackThread&) = delete;
39 RunCallbackThread& operator=(const RunCallbackThread&) = delete;
tommycli@chromium.orgd52426c2013-07-30 19:26:4040
41 private:
fdorayeed5fa72016-07-26 22:28:4542 // SimpleThread:
kylechar01598d72019-05-21 18:35:3143 void Run() override { std::move(callback_).Run(); }
tommycli@chromium.orgd52426c2013-07-30 19:26:4044
kylechar01598d72019-05-21 18:35:3145 OnceClosure callback_;
tommycli@chromium.orgd52426c2013-07-30 19:26:4046};
47
fdoraye2b19a12016-07-29 02:30:1648void ExpectCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
fdorayeed5fa72016-07-26 22:28:4549 ASSERT_TRUE(sequence_checker);
tommycli@chromium.orgd52426c2013-07-30 19:26:4050
fdorayeed5fa72016-07-26 22:28:4551 // This should bind |sequence_checker| to the current sequence if it wasn't
52 // already bound to a sequence.
fdoraye2b19a12016-07-29 02:30:1653 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
tommycli@chromium.orgd52426c2013-07-30 19:26:4054
fdorayeed5fa72016-07-26 22:28:4555 // Since |sequence_checker| is now bound to the current sequence, another call
fdoraye2b19a12016-07-29 02:30:1656 // to CalledOnValidSequence() should return true.
57 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
akalin@chromium.org399ed422012-12-27 19:58:0058}
59
fdoraye2b19a12016-07-29 02:30:1660void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
fdorayeed5fa72016-07-26 22:28:4561 ASSERT_TRUE(sequence_checker);
fdoraye2b19a12016-07-29 02:30:1662 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
tommycli@chromium.orgd52426c2013-07-30 19:26:4063}
64
akalin@chromium.org399ed422012-12-27 19:58:0065} // namespace
66
François Doray524d2a22024-01-04 09:54:1667TEST(SequenceCheckerTest, NoTaskScope) {
fdorayeed5fa72016-07-26 22:28:4568 SequenceCheckerImpl sequence_checker;
fdoraye2b19a12016-07-29 02:30:1669 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
fdorayeed5fa72016-07-26 22:28:4570}
tommycli@chromium.orgd52426c2013-07-30 19:26:4071
François Doray524d2a22024-01-04 09:54:1672TEST(SequenceCheckerTest, TaskScope) {
73 TaskScope task_scope(SequenceToken::Create(),
74 /* is_thread_bound=*/false);
fdorayeed5fa72016-07-26 22:28:4575 SequenceCheckerImpl sequence_checker;
fdoraye2b19a12016-07-29 02:30:1676 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
fdorayeed5fa72016-07-26 22:28:4577}
78
François Doray524d2a22024-01-04 09:54:1679TEST(SequenceCheckerTest, TaskScopeThreadBound) {
80 TaskScope task_scope(SequenceToken::Create(),
81 /* is_thread_bound=*/true);
82 SequenceCheckerImpl sequence_checker;
83 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
84}
85
86TEST(SequenceCheckerTest, DifferentThreadNoTaskScope) {
fdorayeed5fa72016-07-26 22:28:4587 SequenceCheckerImpl sequence_checker;
fdoraye2b19a12016-07-29 02:30:1688 RunCallbackThread thread(
kylechar01598d72019-05-21 18:35:3189 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker)));
fdorayeed5fa72016-07-26 22:28:4590}
91
François Doray524d2a22024-01-04 09:54:1692TEST(SequenceCheckerTest, DifferentThreadDifferentSequenceToken) {
fdorayeed5fa72016-07-26 22:28:4593 SequenceCheckerImpl sequence_checker;
François Doray524d2a22024-01-04 09:54:1694 RunCallbackThread thread(BindLambdaForTesting([&]() {
95 TaskScope task_scope(SequenceToken::Create(),
96 /* is_thread_bound=*/false);
97 ExpectNotCalledOnValidSequence(&sequence_checker);
98 }));
fdorayeed5fa72016-07-26 22:28:4599}
100
François Doray524d2a22024-01-04 09:54:16101TEST(SequenceCheckerTest, DifferentThreadDifferentSequenceTokenThreadBound) {
102 SequenceCheckerImpl sequence_checker;
103 RunCallbackThread thread(BindLambdaForTesting([&]() {
104 TaskScope task_scope(SequenceToken::Create(),
105 /* is_thread_bound=*/true);
106 ExpectNotCalledOnValidSequence(&sequence_checker);
107 }));
108}
109
110TEST(SequenceCheckerTest, DifferentThreadSameSequenceToken) {
111 const SequenceToken token = SequenceToken::Create();
112 TaskScope task_scope(token, /* is_thread_bound=*/false);
113 SequenceCheckerImpl sequence_checker;
114 RunCallbackThread thread(BindLambdaForTesting([&]() {
115 TaskScope task_scope(token, /* is_thread_bound=*/false);
116 ExpectCalledOnValidSequence(&sequence_checker);
117 }));
118}
119
120TEST(SequenceCheckerTest, DifferentThreadSameSequenceTokenThreadBound) {
121 // Note: A callback running synchronously in `RunOrPostTask()` may have a
122 // non-thread-bound `TaskScope` associated with the same `SequenceToken` as
123 // another thread-bound `TaskScope`. This test recreates this case.
124 const SequenceToken token = SequenceToken::Create();
125 TaskScope task_scope(token, /* is_thread_bound=*/true);
126 SequenceCheckerImpl sequence_checker;
127 RunCallbackThread thread(BindLambdaForTesting([&]() {
128 TaskScope task_scope(token, /* is_thread_bound=*/false);
129 ExpectCalledOnValidSequence(&sequence_checker);
130 }));
131}
132
133TEST(SequenceCheckerTest, SameThreadDifferentSequenceToken) {
fdorayeed5fa72016-07-26 22:28:45134 std::unique_ptr<SequenceCheckerImpl> sequence_checker;
135
136 {
François Doray524d2a22024-01-04 09:54:16137 TaskScope task_scope(SequenceToken::Create(),
138 /* is_thread_bound=*/false);
Peter Boströmfd851232021-03-31 17:05:33139 sequence_checker = std::make_unique<SequenceCheckerImpl>();
fdorayeed5fa72016-07-26 22:28:45140 }
141
142 {
143 // Different SequenceToken.
François Doray524d2a22024-01-04 09:54:16144 TaskScope task_scope(SequenceToken::Create(),
145 /* is_thread_bound=*/false);
fdoraye2b19a12016-07-29 02:30:16146 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
fdorayeed5fa72016-07-26 22:28:45147 }
148
François Doray524d2a22024-01-04 09:54:16149 // No explicit SequenceToken.
fdoraye2b19a12016-07-29 02:30:16150 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
fdorayeed5fa72016-07-26 22:28:45151}
152
Francois Doray4914ec142018-02-22 12:48:38153TEST(SequenceCheckerTest, DetachFromSequence) {
fdorayeed5fa72016-07-26 22:28:45154 std::unique_ptr<SequenceCheckerImpl> sequence_checker;
155
156 {
François Doray524d2a22024-01-04 09:54:16157 TaskScope task_scope(SequenceToken::Create(),
158 /* is_thread_bound=*/false);
Peter Boströmfd851232021-03-31 17:05:33159 sequence_checker = std::make_unique<SequenceCheckerImpl>();
fdorayeed5fa72016-07-26 22:28:45160 }
161
162 sequence_checker->DetachFromSequence();
163
164 {
fdoraye2b19a12016-07-29 02:30:16165 // Verify that CalledOnValidSequence() returns true when called with
fdorayeed5fa72016-07-26 22:28:45166 // a different sequence token after a call to DetachFromSequence().
François Doray524d2a22024-01-04 09:54:16167 TaskScope task_scope(SequenceToken::Create(),
168 /* is_thread_bound=*/false);
fdoraye2b19a12016-07-29 02:30:16169 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
fdorayeed5fa72016-07-26 22:28:45170 }
171}
172
Francois Doray4914ec142018-02-22 12:48:38173TEST(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) {
fdorayeed5fa72016-07-26 22:28:45174 SequenceCheckerImpl sequence_checker;
175 sequence_checker.DetachFromSequence();
176
fdoraye2b19a12016-07-29 02:30:16177 // Verify that CalledOnValidSequence() returns true when called on a
fdorayeed5fa72016-07-26 22:28:45178 // different thread after a call to DetachFromSequence().
179 RunCallbackThread thread(
kylechar01598d72019-05-21 18:35:31180 BindOnce(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)));
fdorayeed5fa72016-07-26 22:28:45181
fdoraye2b19a12016-07-29 02:30:16182 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
fdorayeed5fa72016-07-26 22:28:45183}
184
Gabriel Charette9746ffce2019-07-30 20:27:17185TEST(SequenceCheckerTest, Move) {
186 SequenceCheckerImpl initial;
187 EXPECT_TRUE(initial.CalledOnValidSequence());
188
189 SequenceCheckerImpl move_constructed(std::move(initial));
190 EXPECT_TRUE(move_constructed.CalledOnValidSequence());
191
192 SequenceCheckerImpl move_assigned;
193 move_assigned = std::move(move_constructed);
194
195 // The two SequenceCheckerImpls moved from should be able to rebind to another
196 // sequence.
197 RunCallbackThread thread1(
198 BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
199 RunCallbackThread thread2(
200 BindOnce(&ExpectCalledOnValidSequence, Unretained(&move_constructed)));
201
202 // But the latest one shouldn't be able to run on another sequence.
203 RunCallbackThread thread(
204 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
205
206 EXPECT_TRUE(move_assigned.CalledOnValidSequence());
207}
208
209TEST(SequenceCheckerTest, MoveAssignIntoDetached) {
210 SequenceCheckerImpl initial;
211
212 SequenceCheckerImpl move_assigned;
213 move_assigned.DetachFromSequence();
214 move_assigned = std::move(initial);
215
216 // |initial| is detached after move.
217 RunCallbackThread thread1(
218 BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
219
220 // |move_assigned| should be associated with the main thread.
221 RunCallbackThread thread2(
222 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
223
224 EXPECT_TRUE(move_assigned.CalledOnValidSequence());
225}
226
227TEST(SequenceCheckerTest, MoveFromDetachedRebinds) {
228 SequenceCheckerImpl initial;
229 initial.DetachFromSequence();
230
231 SequenceCheckerImpl moved_into(std::move(initial));
232
233 // |initial| is still detached after move.
234 RunCallbackThread thread1(
235 BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
236
237 // |moved_into| is bound to the current sequence as part of the move.
238 RunCallbackThread thread2(
239 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&moved_into)));
240 EXPECT_TRUE(moved_into.CalledOnValidSequence());
241}
242
243TEST(SequenceCheckerTest, MoveOffSequenceBanned) {
Daniel Cheng4ef1552f2023-12-05 02:55:54244 GTEST_FLAG_SET(death_test_style, "threadsafe");
Gabriel Charette9746ffce2019-07-30 20:27:17245
246 SequenceCheckerImpl other_sequence;
247 other_sequence.DetachFromSequence();
248 RunCallbackThread thread(
249 BindOnce(&ExpectCalledOnValidSequence, Unretained(&other_sequence)));
250
251 EXPECT_DCHECK_DEATH(
252 SequenceCheckerImpl main_sequence(std::move(other_sequence)));
253}
254
Francois Doray4914ec142018-02-22 12:48:38255TEST(SequenceCheckerMacroTest, Macros) {
François Doray524d2a22024-01-04 09:54:16256 auto scope = std::make_unique<TaskScope>(SequenceToken::Create(),
257 /* is_thread_bound=*/false);
Francois Doray4914ec142018-02-22 12:48:38258 SEQUENCE_CHECKER(my_sequence_checker);
fdorayeed5fa72016-07-26 22:28:45259
Etienne Pierre-doray841f3e82020-01-14 17:10:25260 {
261 // Don't expect a DCHECK death when a SequenceChecker is used on the right
262 // sequence.
263 DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
264 }
Francois Doray4914ec142018-02-22 12:48:38265 scope.reset();
fdorayeed5fa72016-07-26 22:28:45266
gabd52c912a2017-05-11 04:15:59267#if DCHECK_IS_ON()
Francois Doray4914ec142018-02-22 12:48:38268 // Expect DCHECK death when used on a different sequence.
Etienne Pierre-doray841f3e82020-01-14 17:10:25269 EXPECT_DCHECK_DEATH(
270 { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker); });
gabd52c912a2017-05-11 04:15:59271#else
272 // Happily no-ops on non-dcheck builds.
Etienne Pierre-doray841f3e82020-01-14 17:10:25273 DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
gabd52c912a2017-05-11 04:15:59274#endif
gabd52c912a2017-05-11 04:15:59275
Francois Doray4914ec142018-02-22 12:48:38276 DETACH_FROM_SEQUENCE(my_sequence_checker);
gabd52c912a2017-05-11 04:15:59277
Francois Doray4914ec142018-02-22 12:48:38278 // Don't expect a DCHECK death when a SequenceChecker is used for the first
279 // time after having been detached.
Etienne Pierre-doray841f3e82020-01-14 17:10:25280 DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
gabd52c912a2017-05-11 04:15:59281}
282
Scott Violet909058d2019-07-29 23:07:42283// Owns a SequenceCheckerImpl, and asserts that CalledOnValidSequence() is valid
284// in ~SequenceCheckerOwner.
285class SequenceCheckerOwner {
286 public:
François Doray311bf142024-01-17 19:59:30287 explicit SequenceCheckerOwner(SequenceCheckerImpl* other_checker)
288 : other_checker_(other_checker) {}
David Bienvenu5f4d4f02020-09-27 16:55:03289 SequenceCheckerOwner(const SequenceCheckerOwner&) = delete;
290 SequenceCheckerOwner& operator=(const SequenceCheckerOwner&) = delete;
François Doray311bf142024-01-17 19:59:30291 ~SequenceCheckerOwner() {
292 // Check passes on TLS destruction.
293 EXPECT_TRUE(checker_.CalledOnValidSequence());
294
295 // Check also passes on TLS destruction after move assignment.
296 *other_checker_ = std::move(checker_);
297 EXPECT_TRUE(other_checker_->CalledOnValidSequence());
298 }
Scott Violet909058d2019-07-29 23:07:42299
300 private:
301 SequenceCheckerImpl checker_;
François Doray311bf142024-01-17 19:59:30302 raw_ptr<SequenceCheckerImpl> other_checker_;
Scott Violet909058d2019-07-29 23:07:42303};
304
305// Verifies SequenceCheckerImpl::CalledOnValidSequence() returns true if called
306// during thread destruction.
François Doray524d2a22024-01-04 09:54:16307TEST(SequenceCheckerTest, FromThreadDestruction) {
danakj894364e2021-01-27 21:51:29308 SequenceChecker::EnableStackLogging();
François Doray311bf142024-01-17 19:59:30309
310 SequenceCheckerImpl other_checker;
Scott Violet909058d2019-07-29 23:07:42311 ThreadLocalOwnedPointer<SequenceCheckerOwner> thread_local_owner;
312 {
Gabriel Charette694c3c332019-08-19 14:53:05313 test::TaskEnvironment task_environment;
Gabriel Charette0bcc6ca2020-03-14 00:12:44314 auto task_runner = ThreadPool::CreateSequencedTaskRunner({});
Scott Violet909058d2019-07-29 23:07:42315 task_runner->PostTask(
Sami Kyostila8aa20e70e2019-07-31 17:32:01316 FROM_HERE, BindLambdaForTesting([&]() {
François Doray311bf142024-01-17 19:59:30317 thread_local_owner.Set(
318 std::make_unique<SequenceCheckerOwner>(&other_checker));
Scott Violet909058d2019-07-29 23:07:42319 }));
320 task_runner = nullptr;
321 task_environment.RunUntilIdle();
322 }
323}
324
François Doray524d2a22024-01-04 09:54:16325} // namespace base::internal