From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../pending_task_safety_flag_unittest.cc | 188 +++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 third_party/libwebrtc/api/task_queue/pending_task_safety_flag_unittest.cc (limited to 'third_party/libwebrtc/api/task_queue/pending_task_safety_flag_unittest.cc') diff --git a/third_party/libwebrtc/api/task_queue/pending_task_safety_flag_unittest.cc b/third_party/libwebrtc/api/task_queue/pending_task_safety_flag_unittest.cc new file mode 100644 index 0000000000..cedf0eb8df --- /dev/null +++ b/third_party/libwebrtc/api/task_queue/pending_task_safety_flag_unittest.cc @@ -0,0 +1,188 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/task_queue/pending_task_safety_flag.h" + +#include + +#include "rtc_base/event.h" +#include "rtc_base/logging.h" +#include "rtc_base/task_queue_for_test.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(PendingTaskSafetyFlagTest, Basic) { + rtc::scoped_refptr safety_flag; + { + // Scope for the `owner` instance. + class Owner { + public: + Owner() = default; + ~Owner() { flag_->SetNotAlive(); } + + rtc::scoped_refptr flag_ = + PendingTaskSafetyFlag::Create(); + } owner; + EXPECT_TRUE(owner.flag_->alive()); + safety_flag = owner.flag_; + EXPECT_TRUE(safety_flag->alive()); + } + // `owner` now out of scope. + EXPECT_FALSE(safety_flag->alive()); +} + +TEST(PendingTaskSafetyFlagTest, BasicScoped) { + rtc::scoped_refptr safety_flag; + { + struct Owner { + ScopedTaskSafety safety; + } owner; + safety_flag = owner.safety.flag(); + EXPECT_TRUE(safety_flag->alive()); + } + // `owner` now out of scope. + EXPECT_FALSE(safety_flag->alive()); +} + +TEST(PendingTaskSafetyFlagTest, PendingTaskSuccess) { + TaskQueueForTest tq1("OwnerHere"); + TaskQueueForTest tq2("OwnerNotHere"); + + class Owner { + public: + Owner() : tq_main_(TaskQueueBase::Current()) { RTC_DCHECK(tq_main_); } + ~Owner() { + RTC_DCHECK(tq_main_->IsCurrent()); + flag_->SetNotAlive(); + } + + void DoStuff() { + RTC_DCHECK(!tq_main_->IsCurrent()); + rtc::scoped_refptr safe = flag_; + tq_main_->PostTask([safe = std::move(safe), this]() { + if (!safe->alive()) + return; + stuff_done_ = true; + }); + } + + bool stuff_done() const { return stuff_done_; } + + private: + TaskQueueBase* const tq_main_; + bool stuff_done_ = false; + rtc::scoped_refptr flag_ = + PendingTaskSafetyFlag::Create(); + }; + + std::unique_ptr owner; + tq1.SendTask([&owner]() { + owner = std::make_unique(); + EXPECT_FALSE(owner->stuff_done()); + }); + ASSERT_TRUE(owner); + tq2.SendTask([&owner]() { owner->DoStuff(); }); + tq1.SendTask([&owner]() { + EXPECT_TRUE(owner->stuff_done()); + owner.reset(); + }); + ASSERT_FALSE(owner); +} + +TEST(PendingTaskSafetyFlagTest, PendingTaskDropped) { + TaskQueueForTest tq1("OwnerHere"); + TaskQueueForTest tq2("OwnerNotHere"); + + class Owner { + public: + explicit Owner(bool* stuff_done) + : tq_main_(TaskQueueBase::Current()), stuff_done_(stuff_done) { + RTC_DCHECK(tq_main_); + *stuff_done_ = false; + } + ~Owner() { RTC_DCHECK(tq_main_->IsCurrent()); } + + void DoStuff() { + RTC_DCHECK(!tq_main_->IsCurrent()); + tq_main_->PostTask( + SafeTask(safety_.flag(), [this]() { *stuff_done_ = true; })); + } + + private: + TaskQueueBase* const tq_main_; + bool* const stuff_done_; + ScopedTaskSafety safety_; + }; + + std::unique_ptr owner; + bool stuff_done = false; + tq1.SendTask([&owner, &stuff_done]() { + owner = std::make_unique(&stuff_done); + }); + ASSERT_TRUE(owner); + // Queue up a task on tq1 that will execute before the 'DoStuff' task + // can, and delete the `owner` before the 'stuff' task can execute. + rtc::Event blocker; + tq1.PostTask([&blocker, &owner]() { + blocker.Wait(rtc::Event::kForever); + owner.reset(); + }); + + // Queue up a DoStuff... + tq2.SendTask([&owner]() { owner->DoStuff(); }); + + ASSERT_TRUE(owner); + blocker.Set(); + + // Run an empty task on tq1 to flush all the queued tasks. + tq1.WaitForPreviouslyPostedTasks(); + ASSERT_FALSE(owner); + EXPECT_FALSE(stuff_done); +} + +TEST(PendingTaskSafetyFlagTest, PendingTaskNotAliveInitialized) { + TaskQueueForTest tq("PendingTaskNotAliveInitialized"); + + // Create a new flag that initially not `alive`. + auto flag = PendingTaskSafetyFlag::CreateDetachedInactive(); + tq.SendTask([&flag]() { EXPECT_FALSE(flag->alive()); }); + + bool task_1_ran = false; + bool task_2_ran = false; + tq.PostTask(SafeTask(flag, [&task_1_ran]() { task_1_ran = true; })); + tq.PostTask([&flag]() { flag->SetAlive(); }); + tq.PostTask(SafeTask(flag, [&task_2_ran]() { task_2_ran = true; })); + + tq.WaitForPreviouslyPostedTasks(); + EXPECT_FALSE(task_1_ran); + EXPECT_TRUE(task_2_ran); +} + +TEST(PendingTaskSafetyFlagTest, SafeTask) { + rtc::scoped_refptr flag = + PendingTaskSafetyFlag::Create(); + + int count = 0; + // Create two identical tasks that increment the `count`. + auto task1 = SafeTask(flag, [&count] { ++count; }); + auto task2 = SafeTask(flag, [&count] { ++count; }); + + EXPECT_EQ(count, 0); + std::move(task1)(); + EXPECT_EQ(count, 1); + flag->SetNotAlive(); + // Now task2 should actually not run. + std::move(task2)(); + EXPECT_EQ(count, 1); +} + +} // namespace webrtc -- cgit v1.2.3