1 /*
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
11 #include "rtc_base/task_utils/pending_task_safety_flag.h"
12
13 #include <memory>
14
15 #include "rtc_base/event.h"
16 #include "rtc_base/logging.h"
17 #include "rtc_base/task_queue_for_test.h"
18 #include "rtc_base/task_utils/to_queued_task.h"
19 #include "test/gmock.h"
20 #include "test/gtest.h"
21
22 namespace webrtc {
23 namespace {
24 using ::testing::AtLeast;
25 using ::testing::Invoke;
26 using ::testing::MockFunction;
27 using ::testing::NiceMock;
28 using ::testing::Return;
29 } // namespace
30
TEST(PendingTaskSafetyFlagTest,Basic)31 TEST(PendingTaskSafetyFlagTest, Basic) {
32 rtc::scoped_refptr<PendingTaskSafetyFlag> safety_flag;
33 {
34 // Scope for the |owner| instance.
35 class Owner {
36 public:
37 Owner() = default;
38 ~Owner() { flag_->SetNotAlive(); }
39
40 rtc::scoped_refptr<PendingTaskSafetyFlag> flag_ =
41 PendingTaskSafetyFlag::Create();
42 } owner;
43 EXPECT_TRUE(owner.flag_->alive());
44 safety_flag = owner.flag_;
45 EXPECT_TRUE(safety_flag->alive());
46 }
47 // |owner| now out of scope.
48 EXPECT_FALSE(safety_flag->alive());
49 }
50
TEST(PendingTaskSafetyFlagTest,BasicScoped)51 TEST(PendingTaskSafetyFlagTest, BasicScoped) {
52 rtc::scoped_refptr<PendingTaskSafetyFlag> safety_flag;
53 {
54 struct Owner {
55 ScopedTaskSafety safety;
56 } owner;
57 safety_flag = owner.safety.flag();
58 EXPECT_TRUE(safety_flag->alive());
59 }
60 // |owner| now out of scope.
61 EXPECT_FALSE(safety_flag->alive());
62 }
63
TEST(PendingTaskSafetyFlagTest,PendingTaskSuccess)64 TEST(PendingTaskSafetyFlagTest, PendingTaskSuccess) {
65 TaskQueueForTest tq1("OwnerHere");
66 TaskQueueForTest tq2("OwnerNotHere");
67
68 class Owner {
69 public:
70 Owner() : tq_main_(TaskQueueBase::Current()) { RTC_DCHECK(tq_main_); }
71 ~Owner() {
72 RTC_DCHECK(tq_main_->IsCurrent());
73 flag_->SetNotAlive();
74 }
75
76 void DoStuff() {
77 RTC_DCHECK(!tq_main_->IsCurrent());
78 tq_main_->PostTask(ToQueuedTask([safe = flag_, this]() {
79 if (!safe->alive())
80 return;
81 stuff_done_ = true;
82 }));
83 }
84
85 bool stuff_done() const { return stuff_done_; }
86
87 private:
88 TaskQueueBase* const tq_main_;
89 bool stuff_done_ = false;
90 rtc::scoped_refptr<PendingTaskSafetyFlag> flag_{
91 PendingTaskSafetyFlag::Create()};
92 };
93
94 std::unique_ptr<Owner> owner;
95 tq1.SendTask(
96 [&owner]() {
97 owner.reset(new Owner());
98 EXPECT_FALSE(owner->stuff_done());
99 },
100 RTC_FROM_HERE);
101 ASSERT_TRUE(owner);
102 tq2.SendTask([&owner]() { owner->DoStuff(); }, RTC_FROM_HERE);
103 tq1.SendTask(
104 [&owner]() {
105 EXPECT_TRUE(owner->stuff_done());
106 owner.reset();
107 },
108 RTC_FROM_HERE);
109 ASSERT_FALSE(owner);
110 }
111
TEST(PendingTaskSafetyFlagTest,PendingTaskDropped)112 TEST(PendingTaskSafetyFlagTest, PendingTaskDropped) {
113 TaskQueueForTest tq1("OwnerHere");
114 TaskQueueForTest tq2("OwnerNotHere");
115
116 class Owner {
117 public:
118 explicit Owner(bool* stuff_done)
119 : tq_main_(TaskQueueBase::Current()), stuff_done_(stuff_done) {
120 RTC_DCHECK(tq_main_);
121 *stuff_done_ = false;
122 }
123 ~Owner() {
124 RTC_DCHECK(tq_main_->IsCurrent());
125 }
126
127 void DoStuff() {
128 RTC_DCHECK(!tq_main_->IsCurrent());
129 tq_main_->PostTask(
130 ToQueuedTask(safety_, [this]() { *stuff_done_ = true; }));
131 }
132
133 private:
134 TaskQueueBase* const tq_main_;
135 bool* const stuff_done_;
136 ScopedTaskSafety safety_;
137 };
138
139 std::unique_ptr<Owner> owner;
140 bool stuff_done = false;
141 tq1.SendTask([&owner, &stuff_done]() { owner.reset(new Owner(&stuff_done)); },
142 RTC_FROM_HERE);
143 ASSERT_TRUE(owner);
144 // Queue up a task on tq1 that will execute before the 'DoStuff' task
145 // can, and delete the |owner| before the 'stuff' task can execute.
146 rtc::Event blocker;
147 tq1.PostTask([&blocker, &owner]() {
148 blocker.Wait(rtc::Event::kForever);
149 owner.reset();
150 });
151
152 // Queue up a DoStuff...
153 tq2.SendTask([&owner]() { owner->DoStuff(); }, RTC_FROM_HERE);
154
155 ASSERT_TRUE(owner);
156 blocker.Set();
157
158 // Run an empty task on tq1 to flush all the queued tasks.
159 tq1.SendTask([]() {}, RTC_FROM_HERE);
160 ASSERT_FALSE(owner);
161 EXPECT_FALSE(stuff_done);
162 }
163 } // namespace webrtc
164