tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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