Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors |
akalin@chromium.org | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 5 | #include "base/sequence_checker.h" |
| 6 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 9 | #include <memory> |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 10 | #include <string> |
David Bienvenu | 5f4d4f0 | 2020-09-27 16:55:03 | [diff] [blame] | 11 | #include <utility> |
danakj | 0c8d4aa | 2015-11-25 05:29:58 | [diff] [blame] | 12 | |
Avi Drissman | 63e1f99 | 2023-01-13 18:54:43 | [diff] [blame] | 13 | #include "base/functional/bind.h" |
| 14 | #include "base/functional/callback_helpers.h" |
François Doray | 311bf14 | 2024-01-17 19:59:30 | [diff] [blame] | 15 | #include "base/sequence_checker_impl.h" |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 16 | #include "base/sequence_token.h" |
Patrick Monette | 643cdf6 | 2021-10-15 19:13:42 | [diff] [blame] | 17 | #include "base/task/single_thread_task_runner.h" |
Gabriel Charette | 0bcc6ca | 2020-03-14 00:12:44 | [diff] [blame] | 18 | #include "base/task/thread_pool.h" |
Guido Urdaneta | ef4e9194 | 2020-11-09 15:06:24 | [diff] [blame] | 19 | #include "base/test/bind.h" |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 20 | #include "base/test/gtest_util.h" |
Gabriel Charette | c710874 | 2019-08-23 03:31:40 | [diff] [blame] | 21 | #include "base/test/task_environment.h" |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 22 | #include "base/threading/simple_thread.h" |
Scott Violet | 909058d | 2019-07-29 23:07:42 | [diff] [blame] | 23 | #include "base/threading/thread_local.h" |
dewittj@chromium.org | 8e76597 | 2013-07-26 17:10:02 | [diff] [blame] | 24 | #include "testing/gtest/include/gtest/gtest.h" |
tommycli@chromium.org | 5c0b443 | 2013-07-26 14:23:56 | [diff] [blame] | 25 | |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 26 | namespace base::internal { |
akalin@chromium.org | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 27 | |
| 28 | namespace { |
| 29 | |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 30 | // Runs a callback on another thread. |
| 31 | class RunCallbackThread : public SimpleThread { |
tommycli@chromium.org | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 32 | public: |
kylechar | 01598d7 | 2019-05-21 18:35:31 | [diff] [blame] | 33 | explicit RunCallbackThread(OnceClosure callback) |
| 34 | : SimpleThread("RunCallbackThread"), callback_(std::move(callback)) { |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 35 | Start(); |
| 36 | Join(); |
tommycli@chromium.org | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 37 | } |
David Bienvenu | 5f4d4f0 | 2020-09-27 16:55:03 | [diff] [blame] | 38 | RunCallbackThread(const RunCallbackThread&) = delete; |
| 39 | RunCallbackThread& operator=(const RunCallbackThread&) = delete; |
tommycli@chromium.org | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 40 | |
| 41 | private: |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 42 | // SimpleThread: |
kylechar | 01598d7 | 2019-05-21 18:35:31 | [diff] [blame] | 43 | void Run() override { std::move(callback_).Run(); } |
tommycli@chromium.org | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 44 | |
kylechar | 01598d7 | 2019-05-21 18:35:31 | [diff] [blame] | 45 | OnceClosure callback_; |
tommycli@chromium.org | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 46 | }; |
| 47 | |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 48 | void ExpectCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) { |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 49 | ASSERT_TRUE(sequence_checker); |
tommycli@chromium.org | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 50 | |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 51 | // This should bind |sequence_checker| to the current sequence if it wasn't |
| 52 | // already bound to a sequence. |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 53 | EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); |
tommycli@chromium.org | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 54 | |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 55 | // Since |sequence_checker| is now bound to the current sequence, another call |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 56 | // to CalledOnValidSequence() should return true. |
| 57 | EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); |
akalin@chromium.org | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 58 | } |
| 59 | |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 60 | void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) { |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 61 | ASSERT_TRUE(sequence_checker); |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 62 | EXPECT_FALSE(sequence_checker->CalledOnValidSequence()); |
tommycli@chromium.org | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 63 | } |
| 64 | |
akalin@chromium.org | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 65 | } // namespace |
| 66 | |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 67 | TEST(SequenceCheckerTest, NoTaskScope) { |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 68 | SequenceCheckerImpl sequence_checker; |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 69 | EXPECT_TRUE(sequence_checker.CalledOnValidSequence()); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 70 | } |
tommycli@chromium.org | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 71 | |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 72 | TEST(SequenceCheckerTest, TaskScope) { |
| 73 | TaskScope task_scope(SequenceToken::Create(), |
| 74 | /* is_thread_bound=*/false); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 75 | SequenceCheckerImpl sequence_checker; |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 76 | EXPECT_TRUE(sequence_checker.CalledOnValidSequence()); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 77 | } |
| 78 | |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 79 | TEST(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 | |
| 86 | TEST(SequenceCheckerTest, DifferentThreadNoTaskScope) { |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 87 | SequenceCheckerImpl sequence_checker; |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 88 | RunCallbackThread thread( |
kylechar | 01598d7 | 2019-05-21 18:35:31 | [diff] [blame] | 89 | BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker))); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 90 | } |
| 91 | |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 92 | TEST(SequenceCheckerTest, DifferentThreadDifferentSequenceToken) { |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 93 | SequenceCheckerImpl sequence_checker; |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 94 | RunCallbackThread thread(BindLambdaForTesting([&]() { |
| 95 | TaskScope task_scope(SequenceToken::Create(), |
| 96 | /* is_thread_bound=*/false); |
| 97 | ExpectNotCalledOnValidSequence(&sequence_checker); |
| 98 | })); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 99 | } |
| 100 | |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 101 | TEST(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 | |
| 110 | TEST(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 | |
| 120 | TEST(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 | |
| 133 | TEST(SequenceCheckerTest, SameThreadDifferentSequenceToken) { |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 134 | std::unique_ptr<SequenceCheckerImpl> sequence_checker; |
| 135 | |
| 136 | { |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 137 | TaskScope task_scope(SequenceToken::Create(), |
| 138 | /* is_thread_bound=*/false); |
Peter Boström | fd85123 | 2021-03-31 17:05:33 | [diff] [blame] | 139 | sequence_checker = std::make_unique<SequenceCheckerImpl>(); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | { |
| 143 | // Different SequenceToken. |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 144 | TaskScope task_scope(SequenceToken::Create(), |
| 145 | /* is_thread_bound=*/false); |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 146 | EXPECT_FALSE(sequence_checker->CalledOnValidSequence()); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 147 | } |
| 148 | |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 149 | // No explicit SequenceToken. |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 150 | EXPECT_FALSE(sequence_checker->CalledOnValidSequence()); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 151 | } |
| 152 | |
Francois Doray | 4914ec14 | 2018-02-22 12:48:38 | [diff] [blame] | 153 | TEST(SequenceCheckerTest, DetachFromSequence) { |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 154 | std::unique_ptr<SequenceCheckerImpl> sequence_checker; |
| 155 | |
| 156 | { |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 157 | TaskScope task_scope(SequenceToken::Create(), |
| 158 | /* is_thread_bound=*/false); |
Peter Boström | fd85123 | 2021-03-31 17:05:33 | [diff] [blame] | 159 | sequence_checker = std::make_unique<SequenceCheckerImpl>(); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 160 | } |
| 161 | |
| 162 | sequence_checker->DetachFromSequence(); |
| 163 | |
| 164 | { |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 165 | // Verify that CalledOnValidSequence() returns true when called with |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 166 | // a different sequence token after a call to DetachFromSequence(). |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 167 | TaskScope task_scope(SequenceToken::Create(), |
| 168 | /* is_thread_bound=*/false); |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 169 | EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 170 | } |
| 171 | } |
| 172 | |
Francois Doray | 4914ec14 | 2018-02-22 12:48:38 | [diff] [blame] | 173 | TEST(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) { |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 174 | SequenceCheckerImpl sequence_checker; |
| 175 | sequence_checker.DetachFromSequence(); |
| 176 | |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 177 | // Verify that CalledOnValidSequence() returns true when called on a |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 178 | // different thread after a call to DetachFromSequence(). |
| 179 | RunCallbackThread thread( |
kylechar | 01598d7 | 2019-05-21 18:35:31 | [diff] [blame] | 180 | BindOnce(&ExpectCalledOnValidSequence, Unretained(&sequence_checker))); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 181 | |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 182 | EXPECT_FALSE(sequence_checker.CalledOnValidSequence()); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 183 | } |
| 184 | |
Gabriel Charette | 9746ffce | 2019-07-30 20:27:17 | [diff] [blame] | 185 | TEST(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 | |
| 209 | TEST(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 | |
| 227 | TEST(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 | |
| 243 | TEST(SequenceCheckerTest, MoveOffSequenceBanned) { |
Daniel Cheng | 4ef1552f | 2023-12-05 02:55:54 | [diff] [blame] | 244 | GTEST_FLAG_SET(death_test_style, "threadsafe"); |
Gabriel Charette | 9746ffce | 2019-07-30 20:27:17 | [diff] [blame] | 245 | |
| 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 Doray | 4914ec14 | 2018-02-22 12:48:38 | [diff] [blame] | 255 | TEST(SequenceCheckerMacroTest, Macros) { |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 256 | auto scope = std::make_unique<TaskScope>(SequenceToken::Create(), |
| 257 | /* is_thread_bound=*/false); |
Francois Doray | 4914ec14 | 2018-02-22 12:48:38 | [diff] [blame] | 258 | SEQUENCE_CHECKER(my_sequence_checker); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 259 | |
Etienne Pierre-doray | 841f3e8 | 2020-01-14 17:10:25 | [diff] [blame] | 260 | { |
| 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 Doray | 4914ec14 | 2018-02-22 12:48:38 | [diff] [blame] | 265 | scope.reset(); |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 266 | |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 267 | #if DCHECK_IS_ON() |
Francois Doray | 4914ec14 | 2018-02-22 12:48:38 | [diff] [blame] | 268 | // Expect DCHECK death when used on a different sequence. |
Etienne Pierre-doray | 841f3e8 | 2020-01-14 17:10:25 | [diff] [blame] | 269 | EXPECT_DCHECK_DEATH( |
| 270 | { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker); }); |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 271 | #else |
| 272 | // Happily no-ops on non-dcheck builds. |
Etienne Pierre-doray | 841f3e8 | 2020-01-14 17:10:25 | [diff] [blame] | 273 | DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker); |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 274 | #endif |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 275 | |
Francois Doray | 4914ec14 | 2018-02-22 12:48:38 | [diff] [blame] | 276 | DETACH_FROM_SEQUENCE(my_sequence_checker); |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 277 | |
Francois Doray | 4914ec14 | 2018-02-22 12:48:38 | [diff] [blame] | 278 | // Don't expect a DCHECK death when a SequenceChecker is used for the first |
| 279 | // time after having been detached. |
Etienne Pierre-doray | 841f3e8 | 2020-01-14 17:10:25 | [diff] [blame] | 280 | DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker); |
gab | d52c912a | 2017-05-11 04:15:59 | [diff] [blame] | 281 | } |
| 282 | |
Scott Violet | 909058d | 2019-07-29 23:07:42 | [diff] [blame] | 283 | // Owns a SequenceCheckerImpl, and asserts that CalledOnValidSequence() is valid |
| 284 | // in ~SequenceCheckerOwner. |
| 285 | class SequenceCheckerOwner { |
| 286 | public: |
François Doray | 311bf14 | 2024-01-17 19:59:30 | [diff] [blame] | 287 | explicit SequenceCheckerOwner(SequenceCheckerImpl* other_checker) |
| 288 | : other_checker_(other_checker) {} |
David Bienvenu | 5f4d4f0 | 2020-09-27 16:55:03 | [diff] [blame] | 289 | SequenceCheckerOwner(const SequenceCheckerOwner&) = delete; |
| 290 | SequenceCheckerOwner& operator=(const SequenceCheckerOwner&) = delete; |
François Doray | 311bf14 | 2024-01-17 19:59:30 | [diff] [blame] | 291 | ~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 Violet | 909058d | 2019-07-29 23:07:42 | [diff] [blame] | 299 | |
| 300 | private: |
| 301 | SequenceCheckerImpl checker_; |
François Doray | 311bf14 | 2024-01-17 19:59:30 | [diff] [blame] | 302 | raw_ptr<SequenceCheckerImpl> other_checker_; |
Scott Violet | 909058d | 2019-07-29 23:07:42 | [diff] [blame] | 303 | }; |
| 304 | |
| 305 | // Verifies SequenceCheckerImpl::CalledOnValidSequence() returns true if called |
| 306 | // during thread destruction. |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 307 | TEST(SequenceCheckerTest, FromThreadDestruction) { |
danakj | 894364e | 2021-01-27 21:51:29 | [diff] [blame] | 308 | SequenceChecker::EnableStackLogging(); |
François Doray | 311bf14 | 2024-01-17 19:59:30 | [diff] [blame] | 309 | |
| 310 | SequenceCheckerImpl other_checker; |
Scott Violet | 909058d | 2019-07-29 23:07:42 | [diff] [blame] | 311 | ThreadLocalOwnedPointer<SequenceCheckerOwner> thread_local_owner; |
| 312 | { |
Gabriel Charette | 694c3c33 | 2019-08-19 14:53:05 | [diff] [blame] | 313 | test::TaskEnvironment task_environment; |
Gabriel Charette | 0bcc6ca | 2020-03-14 00:12:44 | [diff] [blame] | 314 | auto task_runner = ThreadPool::CreateSequencedTaskRunner({}); |
Scott Violet | 909058d | 2019-07-29 23:07:42 | [diff] [blame] | 315 | task_runner->PostTask( |
Sami Kyostila | 8aa20e70e | 2019-07-31 17:32:01 | [diff] [blame] | 316 | FROM_HERE, BindLambdaForTesting([&]() { |
François Doray | 311bf14 | 2024-01-17 19:59:30 | [diff] [blame] | 317 | thread_local_owner.Set( |
| 318 | std::make_unique<SequenceCheckerOwner>(&other_checker)); |
Scott Violet | 909058d | 2019-07-29 23:07:42 | [diff] [blame] | 319 | })); |
| 320 | task_runner = nullptr; |
| 321 | task_environment.RunUntilIdle(); |
| 322 | } |
| 323 | } |
| 324 | |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 325 | } // namespace base::internal |