blob: 41f6d7fd801d35a7415fe31a0934942f6db5f157 [file] [log] [blame]
Tommi3c9bcc12020-04-15 14:45:471/*
2 * Copyright 2019 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 Titovc374d112022-06-16 19:27:4511#include "api/task_queue/pending_task_safety_flag.h"
Tommi3c9bcc12020-04-15 14:45:4712
13#include <memory>
Dor Hen5ac2c742024-08-05 08:21:0214#include <utility>
Tommi3c9bcc12020-04-15 14:45:4715
Dor Hen5ac2c742024-08-05 08:21:0216#include "api/scoped_refptr.h"
17#include "api/task_queue/task_queue_base.h"
18#include "rtc_base/checks.h"
Tommi3c9bcc12020-04-15 14:45:4719#include "rtc_base/event.h"
Tommi3c9bcc12020-04-15 14:45:4720#include "rtc_base/task_queue_for_test.h"
Tommi3c9bcc12020-04-15 14:45:4721#include "test/gtest.h"
22
23namespace webrtc {
Tommi3c9bcc12020-04-15 14:45:4724
25TEST(PendingTaskSafetyFlagTest, Basic) {
Tommia98cea82020-05-13 13:06:1926 rtc::scoped_refptr<PendingTaskSafetyFlag> safety_flag;
Tommi3c9bcc12020-04-15 14:45:4727 {
Artem Titov96e3b992021-07-26 14:03:1428 // Scope for the `owner` instance.
Tommi3c9bcc12020-04-15 14:45:4729 class Owner {
30 public:
31 Owner() = default;
32 ~Owner() { flag_->SetNotAlive(); }
33
Tommia98cea82020-05-13 13:06:1934 rtc::scoped_refptr<PendingTaskSafetyFlag> flag_ =
35 PendingTaskSafetyFlag::Create();
Tommi3c9bcc12020-04-15 14:45:4736 } owner;
37 EXPECT_TRUE(owner.flag_->alive());
38 safety_flag = owner.flag_;
39 EXPECT_TRUE(safety_flag->alive());
40 }
Artem Titov96e3b992021-07-26 14:03:1441 // `owner` now out of scope.
Tommia98cea82020-05-13 13:06:1942 EXPECT_FALSE(safety_flag->alive());
43}
44
45TEST(PendingTaskSafetyFlagTest, BasicScoped) {
46 rtc::scoped_refptr<PendingTaskSafetyFlag> safety_flag;
47 {
48 struct Owner {
49 ScopedTaskSafety safety;
50 } owner;
51 safety_flag = owner.safety.flag();
52 EXPECT_TRUE(safety_flag->alive());
53 }
Artem Titov96e3b992021-07-26 14:03:1454 // `owner` now out of scope.
Tommi3c9bcc12020-04-15 14:45:4755 EXPECT_FALSE(safety_flag->alive());
56}
57
58TEST(PendingTaskSafetyFlagTest, PendingTaskSuccess) {
59 TaskQueueForTest tq1("OwnerHere");
60 TaskQueueForTest tq2("OwnerNotHere");
61
62 class Owner {
63 public:
64 Owner() : tq_main_(TaskQueueBase::Current()) { RTC_DCHECK(tq_main_); }
65 ~Owner() {
66 RTC_DCHECK(tq_main_->IsCurrent());
67 flag_->SetNotAlive();
68 }
69
70 void DoStuff() {
71 RTC_DCHECK(!tq_main_->IsCurrent());
Danil Chapovalova7e15a22022-07-05 14:03:0372 rtc::scoped_refptr<PendingTaskSafetyFlag> safe = flag_;
73 tq_main_->PostTask([safe = std::move(safe), this]() {
Tommi3c9bcc12020-04-15 14:45:4774 if (!safe->alive())
75 return;
76 stuff_done_ = true;
Danil Chapovalova7e15a22022-07-05 14:03:0377 });
Tommi3c9bcc12020-04-15 14:45:4778 }
79
80 bool stuff_done() const { return stuff_done_; }
81
82 private:
83 TaskQueueBase* const tq_main_;
84 bool stuff_done_ = false;
Danil Chapovalova7e15a22022-07-05 14:03:0385 rtc::scoped_refptr<PendingTaskSafetyFlag> flag_ =
86 PendingTaskSafetyFlag::Create();
Tommi3c9bcc12020-04-15 14:45:4787 };
88
89 std::unique_ptr<Owner> owner;
Danil Chapovalove519f382022-08-11 10:26:0990 tq1.SendTask([&owner]() {
91 owner = std::make_unique<Owner>();
92 EXPECT_FALSE(owner->stuff_done());
93 });
Tommi3c9bcc12020-04-15 14:45:4794 ASSERT_TRUE(owner);
Danil Chapovalove519f382022-08-11 10:26:0995 tq2.SendTask([&owner]() { owner->DoStuff(); });
96 tq1.SendTask([&owner]() {
97 EXPECT_TRUE(owner->stuff_done());
98 owner.reset();
99 });
Tommi3c9bcc12020-04-15 14:45:47100 ASSERT_FALSE(owner);
101}
102
103TEST(PendingTaskSafetyFlagTest, PendingTaskDropped) {
104 TaskQueueForTest tq1("OwnerHere");
105 TaskQueueForTest tq2("OwnerNotHere");
106
107 class Owner {
108 public:
109 explicit Owner(bool* stuff_done)
110 : tq_main_(TaskQueueBase::Current()), stuff_done_(stuff_done) {
111 RTC_DCHECK(tq_main_);
112 *stuff_done_ = false;
113 }
Artem Titovc374d112022-06-16 19:27:45114 ~Owner() { RTC_DCHECK(tq_main_->IsCurrent()); }
Tommi3c9bcc12020-04-15 14:45:47115
116 void DoStuff() {
117 RTC_DCHECK(!tq_main_->IsCurrent());
Tommia98cea82020-05-13 13:06:19118 tq_main_->PostTask(
Danil Chapovalova7e15a22022-07-05 14:03:03119 SafeTask(safety_.flag(), [this]() { *stuff_done_ = true; }));
Tommi3c9bcc12020-04-15 14:45:47120 }
121
122 private:
123 TaskQueueBase* const tq_main_;
124 bool* const stuff_done_;
Tommia98cea82020-05-13 13:06:19125 ScopedTaskSafety safety_;
Tommi3c9bcc12020-04-15 14:45:47126 };
127
128 std::unique_ptr<Owner> owner;
129 bool stuff_done = false;
Danil Chapovalove519f382022-08-11 10:26:09130 tq1.SendTask([&owner, &stuff_done]() {
131 owner = std::make_unique<Owner>(&stuff_done);
132 });
Tommi3c9bcc12020-04-15 14:45:47133 ASSERT_TRUE(owner);
134 // Queue up a task on tq1 that will execute before the 'DoStuff' task
Artem Titov96e3b992021-07-26 14:03:14135 // can, and delete the `owner` before the 'stuff' task can execute.
Tommi3c9bcc12020-04-15 14:45:47136 rtc::Event blocker;
137 tq1.PostTask([&blocker, &owner]() {
138 blocker.Wait(rtc::Event::kForever);
139 owner.reset();
140 });
141
142 // Queue up a DoStuff...
Danil Chapovalove519f382022-08-11 10:26:09143 tq2.SendTask([&owner]() { owner->DoStuff(); });
Tommi3c9bcc12020-04-15 14:45:47144
145 ASSERT_TRUE(owner);
146 blocker.Set();
147
148 // Run an empty task on tq1 to flush all the queued tasks.
Tomas Gunnarsson25e73522021-04-19 08:14:10149 tq1.WaitForPreviouslyPostedTasks();
Tommi3c9bcc12020-04-15 14:45:47150 ASSERT_FALSE(owner);
151 EXPECT_FALSE(stuff_done);
152}
Tomas Gunnarsson25e73522021-04-19 08:14:10153
154TEST(PendingTaskSafetyFlagTest, PendingTaskNotAliveInitialized) {
155 TaskQueueForTest tq("PendingTaskNotAliveInitialized");
156
157 // Create a new flag that initially not `alive`.
158 auto flag = PendingTaskSafetyFlag::CreateDetachedInactive();
Danil Chapovalove519f382022-08-11 10:26:09159 tq.SendTask([&flag]() { EXPECT_FALSE(flag->alive()); });
Tomas Gunnarsson25e73522021-04-19 08:14:10160
161 bool task_1_ran = false;
162 bool task_2_ran = false;
Danil Chapovalova7e15a22022-07-05 14:03:03163 tq.PostTask(SafeTask(flag, [&task_1_ran]() { task_1_ran = true; }));
Tomas Gunnarsson25e73522021-04-19 08:14:10164 tq.PostTask([&flag]() { flag->SetAlive(); });
Danil Chapovalova7e15a22022-07-05 14:03:03165 tq.PostTask(SafeTask(flag, [&task_2_ran]() { task_2_ran = true; }));
Tomas Gunnarsson25e73522021-04-19 08:14:10166
167 tq.WaitForPreviouslyPostedTasks();
168 EXPECT_FALSE(task_1_ran);
169 EXPECT_TRUE(task_2_ran);
170}
171
Tommi8da59532023-10-24 21:43:56172TEST(PendingTaskSafetyFlagTest, PendingTaskInitializedForTaskQueue) {
173 TaskQueueForTest tq("PendingTaskAliveInitializedForTaskQueue");
174
175 // Create a new flag that initially `alive`, attached to a specific TQ.
176 auto flag = PendingTaskSafetyFlag::CreateAttachedToTaskQueue(true, tq.Get());
177 tq.SendTask([&flag]() { EXPECT_TRUE(flag->alive()); });
178 // Repeat the same steps but initialize as inactive.
179 flag = PendingTaskSafetyFlag::CreateAttachedToTaskQueue(false, tq.Get());
180 tq.SendTask([&flag]() { EXPECT_FALSE(flag->alive()); });
181}
182
Danil Chapovalova7e15a22022-07-05 14:03:03183TEST(PendingTaskSafetyFlagTest, SafeTask) {
184 rtc::scoped_refptr<PendingTaskSafetyFlag> flag =
185 PendingTaskSafetyFlag::Create();
186
187 int count = 0;
188 // Create two identical tasks that increment the `count`.
189 auto task1 = SafeTask(flag, [&count] { ++count; });
190 auto task2 = SafeTask(flag, [&count] { ++count; });
191
192 EXPECT_EQ(count, 0);
193 std::move(task1)();
194 EXPECT_EQ(count, 1);
195 flag->SetNotAlive();
196 // Now task2 should actually not run.
197 std::move(task2)();
198 EXPECT_EQ(count, 1);
199}
200
Tommi3c9bcc12020-04-15 14:45:47201} // namespace webrtc