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