pending_task_safety_flag_unittest.cc (5784B)
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 "api/task_queue/pending_task_safety_flag.h" 12 13 #include <memory> 14 #include <utility> 15 16 #include "api/scoped_refptr.h" 17 #include "api/task_queue/task_queue_base.h" 18 #include "rtc_base/checks.h" 19 #include "rtc_base/event.h" 20 #include "rtc_base/task_queue_for_test.h" 21 #include "test/gtest.h" 22 23 namespace webrtc { 24 25 TEST(PendingTaskSafetyFlagTest, Basic) { 26 scoped_refptr<PendingTaskSafetyFlag> safety_flag; 27 { 28 // Scope for the `owner` instance. 29 class Owner { 30 public: 31 Owner() = default; 32 ~Owner() { flag_->SetNotAlive(); } 33 34 scoped_refptr<PendingTaskSafetyFlag> flag_ = 35 PendingTaskSafetyFlag::Create(); 36 } owner; 37 EXPECT_TRUE(owner.flag_->alive()); 38 safety_flag = owner.flag_; 39 EXPECT_TRUE(safety_flag->alive()); 40 } 41 // `owner` now out of scope. 42 EXPECT_FALSE(safety_flag->alive()); 43 } 44 45 TEST(PendingTaskSafetyFlagTest, BasicScoped) { 46 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 } 54 // `owner` now out of scope. 55 EXPECT_FALSE(safety_flag->alive()); 56 } 57 58 TEST(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()); 72 scoped_refptr<PendingTaskSafetyFlag> safe = flag_; 73 tq_main_->PostTask([safe = std::move(safe), this]() { 74 if (!safe->alive()) 75 return; 76 stuff_done_ = true; 77 }); 78 } 79 80 bool stuff_done() const { return stuff_done_; } 81 82 private: 83 TaskQueueBase* const tq_main_; 84 bool stuff_done_ = false; 85 scoped_refptr<PendingTaskSafetyFlag> flag_ = 86 PendingTaskSafetyFlag::Create(); 87 }; 88 89 std::unique_ptr<Owner> owner; 90 tq1.SendTask([&owner]() { 91 owner = std::make_unique<Owner>(); 92 EXPECT_FALSE(owner->stuff_done()); 93 }); 94 ASSERT_TRUE(owner); 95 tq2.SendTask([&owner]() { owner->DoStuff(); }); 96 tq1.SendTask([&owner]() { 97 EXPECT_TRUE(owner->stuff_done()); 98 owner.reset(); 99 }); 100 ASSERT_FALSE(owner); 101 } 102 103 TEST(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 } 114 ~Owner() { RTC_DCHECK(tq_main_->IsCurrent()); } 115 116 void DoStuff() { 117 RTC_DCHECK(!tq_main_->IsCurrent()); 118 tq_main_->PostTask( 119 SafeTask(safety_.flag(), [this]() { *stuff_done_ = true; })); 120 } 121 122 private: 123 TaskQueueBase* const tq_main_; 124 bool* const stuff_done_; 125 ScopedTaskSafety safety_; 126 }; 127 128 std::unique_ptr<Owner> owner; 129 bool stuff_done = false; 130 tq1.SendTask([&owner, &stuff_done]() { 131 owner = std::make_unique<Owner>(&stuff_done); 132 }); 133 ASSERT_TRUE(owner); 134 // Queue up a task on tq1 that will execute before the 'DoStuff' task 135 // can, and delete the `owner` before the 'stuff' task can execute. 136 Event blocker; 137 tq1.PostTask([&blocker, &owner]() { 138 blocker.Wait(Event::kForever); 139 owner.reset(); 140 }); 141 142 // Queue up a DoStuff... 143 tq2.SendTask([&owner]() { owner->DoStuff(); }); 144 145 ASSERT_TRUE(owner); 146 blocker.Set(); 147 148 // Run an empty task on tq1 to flush all the queued tasks. 149 tq1.WaitForPreviouslyPostedTasks(); 150 ASSERT_FALSE(owner); 151 EXPECT_FALSE(stuff_done); 152 } 153 154 TEST(PendingTaskSafetyFlagTest, PendingTaskNotAliveInitialized) { 155 TaskQueueForTest tq("PendingTaskNotAliveInitialized"); 156 157 // Create a new flag that initially not `alive`. 158 auto flag = PendingTaskSafetyFlag::CreateDetachedInactive(); 159 tq.SendTask([&flag]() { EXPECT_FALSE(flag->alive()); }); 160 161 bool task_1_ran = false; 162 bool task_2_ran = false; 163 tq.PostTask(SafeTask(flag, [&task_1_ran]() { task_1_ran = true; })); 164 tq.PostTask([&flag]() { flag->SetAlive(); }); 165 tq.PostTask(SafeTask(flag, [&task_2_ran]() { task_2_ran = true; })); 166 167 tq.WaitForPreviouslyPostedTasks(); 168 EXPECT_FALSE(task_1_ran); 169 EXPECT_TRUE(task_2_ran); 170 } 171 172 TEST(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 183 TEST(PendingTaskSafetyFlagTest, SafeTask) { 184 scoped_refptr<PendingTaskSafetyFlag> flag = PendingTaskSafetyFlag::Create(); 185 186 int count = 0; 187 // Create two identical tasks that increment the `count`. 188 auto task1 = SafeTask(flag, [&count] { ++count; }); 189 auto task2 = SafeTask(flag, [&count] { ++count; }); 190 191 EXPECT_EQ(count, 0); 192 std::move(task1)(); 193 EXPECT_EQ(count, 1); 194 flag->SetNotAlive(); 195 // Now task2 should actually not run. 196 std::move(task2)(); 197 EXPECT_EQ(count, 1); 198 } 199 200 } // namespace webrtc