Thanks to visit codestin.com
Credit goes to webrtc.googlesource.com

blob: a29bd6cd11ccf7c47ddff3024cd724f19e7e33cf [file] [log] [blame]
Sebastian Janssonb55015e2019-04-09 11:44:041/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Artem Titovb586d822021-02-04 14:06:5011#include "api/sequence_checker.h"
Sebastian Janssonb55015e2019-04-09 11:44:0412
Dor Henaefed552024-06-18 13:20:3513#include <functional>
Sebastian Janssonb55015e2019-04-09 11:44:0414#include <memory>
Tommid4871e22025-09-29 20:17:1315#include <utility>
16#include <vector>
Sebastian Janssonb55015e2019-04-09 11:44:0417
Dor Henaefed552024-06-18 13:20:3518#include "absl/functional/any_invocable.h"
Sebastian Janssonb55015e2019-04-09 11:44:0419#include "api/function_view.h"
Markus Handell2cfc1af2022-08-19 08:16:4820#include "api/units/time_delta.h"
Dor Henaefed552024-06-18 13:20:3521#include "rtc_base/checks.h"
Sebastian Janssonb55015e2019-04-09 11:44:0422#include "rtc_base/event.h"
23#include "rtc_base/platform_thread.h"
Dor Henaefed552024-06-18 13:20:3524#include "rtc_base/synchronization/sequence_checker_internal.h"
Tommid4871e22025-09-29 20:17:1325#include "rtc_base/system/unused.h"
Sebastian Janssonb55015e2019-04-09 11:44:0426#include "rtc_base/task_queue_for_test.h"
Dor Henaefed552024-06-18 13:20:3527#include "rtc_base/thread_annotations.h"
Byoungchan Lee40867212022-09-26 14:24:0428#include "test/gmock.h"
Sebastian Janssonb55015e2019-04-09 11:44:0429#include "test/gtest.h"
30
Byoungchan Lee40867212022-09-26 14:24:0431using testing::HasSubstr;
32
Sebastian Janssonb55015e2019-04-09 11:44:0433namespace webrtc {
34namespace {
35
36// This class is dead code, but its purpose is to make sure that
37// SequenceChecker is compatible with the RTC_GUARDED_BY and RTC_RUN_ON
38// attributes that are checked at compile-time.
39class CompileTimeTestForGuardedBy {
40 public:
41 int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
42
43 void CallMeFromSequence() {
Tomas Gunnarsson4d177eb2020-06-08 21:08:4644 RTC_DCHECK_RUN_ON(&sequence_checker_);
Sebastian Janssonb55015e2019-04-09 11:44:0445 guarded_ = 41;
46 }
47
48 private:
49 int guarded_ RTC_GUARDED_BY(sequence_checker_);
Evan Shrubsole2f5c2662025-05-12 07:43:0950 SequenceChecker sequence_checker_;
Sebastian Janssonb55015e2019-04-09 11:44:0451};
52
Evan Shrubsole97feff22025-03-12 09:13:4553void RunOnDifferentThread(FunctionView<void()> run) {
Evan Shrubsole39c1c7e2025-03-20 10:10:5054 Event thread_has_run_event;
Evan Shrubsole6a9a1ae2025-03-21 12:54:1555 PlatformThread::SpawnJoinable(
Markus Handellad5037b2021-05-07 13:02:3656 [&] {
57 run();
58 thread_has_run_event.Set();
59 },
60 "thread");
Markus Handell2cfc1af2022-08-19 08:16:4861 EXPECT_TRUE(thread_has_run_event.Wait(TimeDelta::Seconds(1)));
Sebastian Janssonb55015e2019-04-09 11:44:0462}
63
64} // namespace
65
66TEST(SequenceCheckerTest, CallsAllowedOnSameThread) {
67 SequenceChecker sequence_checker;
68 EXPECT_TRUE(sequence_checker.IsCurrent());
69}
70
71TEST(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
Mirko Bonadei317a1f02019-09-17 15:06:1872 auto sequence_checker = std::make_unique<SequenceChecker>();
Sebastian Janssonb55015e2019-04-09 11:44:0473 RunOnDifferentThread([&] {
74 // Verify that the destructor doesn't assert when called on a different
75 // thread.
76 sequence_checker.reset();
77 });
78}
79
80TEST(SequenceCheckerTest, Detach) {
81 SequenceChecker sequence_checker;
82 sequence_checker.Detach();
83 RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
84}
85
86TEST(SequenceCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
87 SequenceChecker sequence_checker;
88 sequence_checker.Detach();
89 TaskQueueForTest queue;
Danil Chapovalove519f382022-08-11 10:26:0990 queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
Sebastian Janssonb55015e2019-04-09 11:44:0491}
92
Tommi7c1ddb72023-10-23 12:38:1393TEST(SequenceCheckerTest, InitializeForDifferentTaskQueue) {
94 TaskQueueForTest queue;
95 SequenceChecker sequence_checker(queue.Get());
96 EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON);
97 queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
98}
99
Sebastian Janssonb55015e2019-04-09 11:44:04100TEST(SequenceCheckerTest, DetachFromTaskQueueAndUseOnThread) {
101 TaskQueueForTest queue;
Danil Chapovalove519f382022-08-11 10:26:09102 queue.SendTask([] {
103 SequenceChecker sequence_checker;
104 sequence_checker.Detach();
105 RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
106 });
Sebastian Janssonb55015e2019-04-09 11:44:04107}
108
109TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
Tommid4871e22025-09-29 20:17:13110 SequenceChecker sequence_checker(SequenceChecker::kAttached);
Sebastian Janssonb55015e2019-04-09 11:44:04111 RunOnDifferentThread(
112 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
113}
114
Tommid4871e22025-09-29 20:17:13115TEST(SequenceCheckerTest, DefaultDetachedMethodAllowedOnDifferentThread) {
116 SequenceChecker sequence_checker;
117#if RTC_DCHECK_IS_ON
118 EXPECT_THAT(ExpectationToString(&sequence_checker),
119 HasSubstr("not attached"));
120#endif
121 RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
122}
123
124TEST(SequenceCheckerTest, MoveSemanticsDetach) {
125 SequenceChecker sequence_checker;
126#if RTC_DCHECK_IS_ON
127 EXPECT_THAT(ExpectationToString(&sequence_checker),
128 HasSubstr("not attached"));
129#endif
130 EXPECT_TRUE(sequence_checker.IsCurrent());
131#if RTC_DCHECK_IS_ON
132 EXPECT_THAT(ExpectationToString(&sequence_checker),
133 HasSubstr("# Expected: TQ:"));
134#endif
135 // Moving away from `sequence_checker` will detach from the current
136 // context and the `moved_to` checker will alsy be detached.
137 SequenceChecker moved_to(std::move(sequence_checker));
138#if RTC_DCHECK_IS_ON
139 EXPECT_THAT(ExpectationToString(&sequence_checker),
140 HasSubstr("not attached"));
141 EXPECT_THAT(ExpectationToString(&moved_to), HasSubstr("not attached"));
142#endif
143 RTC_UNUSED(moved_to);
144}
145
146TEST(SequenceCheckerTest, VectorSupport) {
147 std::vector<SequenceChecker> checkers;
148 checkers.push_back(SequenceChecker());
149#if RTC_DCHECK_IS_ON
150 EXPECT_THAT(ExpectationToString(&checkers[0]), HasSubstr("not attached"));
151#endif
152 EXPECT_TRUE(checkers[0].IsCurrent());
153}
154
Tommi301e5462023-05-08 20:03:08155#if RTC_DCHECK_IS_ON
156TEST(SequenceCheckerTest, OnlyCurrentOnOneThread) {
157 SequenceChecker sequence_checker(SequenceChecker::kDetached);
158 RunOnDifferentThread([&] {
159 EXPECT_TRUE(sequence_checker.IsCurrent());
160 // Spawn a new thread from within the first one to guarantee that we have
161 // two concurrently active threads (and that there's no chance of the
162 // thread ref being reused).
163 RunOnDifferentThread([&] { EXPECT_FALSE(sequence_checker.IsCurrent()); });
164 });
165}
166#endif
167
Sebastian Janssonb55015e2019-04-09 11:44:04168TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
Tommid4871e22025-09-29 20:17:13169 SequenceChecker sequence_checker(SequenceChecker::kAttached);
Sebastian Janssonb55015e2019-04-09 11:44:04170 TaskQueueForTest queue;
171 queue.SendTask(
Danil Chapovalove519f382022-08-11 10:26:09172 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
Sebastian Janssonb55015e2019-04-09 11:44:04173}
174
175TEST(SequenceCheckerTest, DetachFromTaskQueueInDebug) {
176 SequenceChecker sequence_checker;
177 sequence_checker.Detach();
178
179 TaskQueueForTest queue1;
Danil Chapovalove519f382022-08-11 10:26:09180 queue1.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
Sebastian Janssonb55015e2019-04-09 11:44:04181
182 // IsCurrent should return false in debug builds after moving to
183 // another task queue.
184 TaskQueueForTest queue2;
185 queue2.SendTask(
Danil Chapovalove519f382022-08-11 10:26:09186 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
Sebastian Janssonb55015e2019-04-09 11:44:04187}
188
Byoungchan Lee40867212022-09-26 14:24:04189TEST(SequenceCheckerTest, ExpectationToString) {
190 TaskQueueForTest queue1;
191
Tommi3da04a92023-03-21 10:42:27192 SequenceChecker sequence_checker(SequenceChecker::kDetached);
Byoungchan Lee40867212022-09-26 14:24:04193
Evan Shrubsole39c1c7e2025-03-20 10:10:50194 Event blocker;
Byoungchan Lee40867212022-09-26 14:24:04195 queue1.PostTask([&blocker, &sequence_checker]() {
196 (void)sequence_checker.IsCurrent();
197 blocker.Set();
198 });
199
Evan Shrubsole39c1c7e2025-03-20 10:10:50200 blocker.Wait(Event::kForever);
Byoungchan Lee40867212022-09-26 14:24:04201
202#if RTC_DCHECK_IS_ON
203
204 EXPECT_THAT(ExpectationToString(&sequence_checker),
205 HasSubstr("# Expected: TQ:"));
206
207 // Test for the base class
208 webrtc_sequence_checker_internal::SequenceCheckerImpl* sequence_checker_base =
209 &sequence_checker;
210 EXPECT_THAT(ExpectationToString(sequence_checker_base),
211 HasSubstr("# Expected: TQ:"));
212
213#else
214 GTEST_ASSERT_EQ(ExpectationToString(&sequence_checker), "");
215#endif
216}
217
Tommi3da04a92023-03-21 10:42:27218TEST(SequenceCheckerTest, InitiallyDetached) {
219 TaskQueueForTest queue1;
220
221 SequenceChecker sequence_checker(SequenceChecker::kDetached);
222
Evan Shrubsole39c1c7e2025-03-20 10:10:50223 Event blocker;
Tommi3da04a92023-03-21 10:42:27224 queue1.PostTask([&blocker, &sequence_checker]() {
225 EXPECT_TRUE(sequence_checker.IsCurrent());
226 blocker.Set();
227 });
228
Evan Shrubsole39c1c7e2025-03-20 10:10:50229 blocker.Wait(Event::kForever);
Tommi3da04a92023-03-21 10:42:27230
231#if RTC_DCHECK_IS_ON
232 EXPECT_FALSE(sequence_checker.IsCurrent());
233#endif
234}
235
Sebastian Janssonb55015e2019-04-09 11:44:04236class TestAnnotations {
237 public:
238 TestAnnotations() : test_var_(false) {}
239
240 void ModifyTestVar() {
241 RTC_DCHECK_RUN_ON(&checker_);
242 test_var_ = true;
243 }
244
245 private:
246 bool test_var_ RTC_GUARDED_BY(&checker_);
Tommid4871e22025-09-29 20:17:13247 SequenceChecker checker_{SequenceChecker::kAttached};
Sebastian Janssonb55015e2019-04-09 11:44:04248};
249
250TEST(SequenceCheckerTest, TestAnnotations) {
251 TestAnnotations annotations;
252 annotations.ModifyTestVar();
253}
254
255#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
256
257void TestAnnotationsOnWrongQueue() {
258 TestAnnotations annotations;
259 TaskQueueForTest queue;
Danil Chapovalove519f382022-08-11 10:26:09260 queue.SendTask([&] { annotations.ModifyTestVar(); });
Sebastian Janssonb55015e2019-04-09 11:44:04261}
262
263#if RTC_DCHECK_IS_ON
Tommiec3ba732020-05-17 12:33:40264// Note: Ending the test suite name with 'DeathTest' is important as it causes
265// gtest to order this test before any other non-death-tests, to avoid potential
266// global process state pollution such as shared worker threads being started
267// (e.g. a side effect of calling InitCocoaMultiThreading() on Mac causes one or
268// two additional threads to be created).
269TEST(SequenceCheckerDeathTest, TestAnnotationsOnWrongQueueDebug) {
Sebastian Janssonb55015e2019-04-09 11:44:04270 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
271}
272#else
273TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueRelease) {
274 TestAnnotationsOnWrongQueue();
275}
276#endif
277#endif // GTEST_HAS_DEATH_TEST
Sebastian Janssonb55015e2019-04-09 11:44:04278} // namespace webrtc