Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 14:04:28 +01:00
parent 81b91f4139
commit f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions

View file

@ -0,0 +1,25 @@
/*
* 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.
*/
#ifndef API_TASK_QUEUE_DEFAULT_TASK_QUEUE_FACTORY_H_
#define API_TASK_QUEUE_DEFAULT_TASK_QUEUE_FACTORY_H_
#include <memory>
#include "api/field_trials_view.h"
#include "api/task_queue/task_queue_factory.h"
namespace webrtc {
std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory(
const FieldTrialsView* field_trials = nullptr);
} // namespace webrtc
#endif // API_TASK_QUEUE_DEFAULT_TASK_QUEUE_FACTORY_H_

View file

@ -0,0 +1,23 @@
/*
* 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 <memory>
#include "api/field_trials_view.h"
#include "api/task_queue/task_queue_factory.h"
#include "rtc_base/task_queue_gcd.h"
namespace webrtc {
std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory(
const FieldTrialsView* field_trials) {
return CreateTaskQueueGcdFactory();
}
} // namespace webrtc

View file

@ -0,0 +1,23 @@
/*
* 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 <memory>
#include "api/field_trials_view.h"
#include "api/task_queue/task_queue_factory.h"
#include "rtc_base/task_queue_libevent.h"
namespace webrtc {
std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory(
const FieldTrialsView* field_trials) {
return CreateTaskQueueLibeventFactory();
}
} // namespace webrtc

View file

@ -0,0 +1,23 @@
/*
* 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 <memory>
#include "api/field_trials_view.h"
#include "api/task_queue/task_queue_factory.h"
#include "rtc_base/task_queue_stdlib.h"
namespace webrtc {
std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory(
const FieldTrialsView* field_trials) {
return CreateTaskQueueStdlibFactory();
}
} // namespace webrtc

View file

@ -0,0 +1,38 @@
/*
* Copyright 2022 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 <memory>
#include "api/field_trials_view.h"
#include "api/task_queue/task_queue_factory.h"
#include "api/transport/field_trial_based_config.h"
#include "rtc_base/logging.h"
#include "rtc_base/memory/always_valid_pointer.h"
#include "rtc_base/task_queue_libevent.h"
#include "rtc_base/task_queue_stdlib.h"
namespace webrtc {
std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory(
const FieldTrialsView* field_trials_view) {
AlwaysValidPointer<const FieldTrialsView, FieldTrialBasedConfig> field_trials(
field_trials_view);
if (field_trials->IsEnabled("WebRTC-TaskQueue-ReplaceLibeventWithStdlib")) {
RTC_LOG(LS_INFO) << "WebRTC-TaskQueue-ReplaceLibeventWithStdlib: "
<< "using TaskQueueStdlibFactory.";
return CreateTaskQueueStdlibFactory();
}
RTC_LOG(LS_INFO) << "WebRTC-TaskQueue-ReplaceLibeventWithStdlib: "
<< "using TaskQueueLibeventFactory.";
return CreateTaskQueueLibeventFactory();
}
} // namespace webrtc

View file

@ -0,0 +1,24 @@
/*
* 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/default_task_queue_factory.h"
#include "api/task_queue/task_queue_test.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
INSTANTIATE_TEST_SUITE_P(Default,
TaskQueueTest,
::testing::Values(CreateDefaultTaskQueueFactory));
} // namespace
} // namespace webrtc

View file

@ -0,0 +1,23 @@
/*
* 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 <memory>
#include "api/field_trials_view.h"
#include "api/task_queue/task_queue_factory.h"
#include "rtc_base/task_queue_win.h"
namespace webrtc {
std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory(
const FieldTrialsView* field_trials) {
return CreateTaskQueueWinFactory();
}
} // namespace webrtc

View file

@ -0,0 +1,68 @@
/*
* Copyright 2020 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"
namespace webrtc {
// static
rtc::scoped_refptr<PendingTaskSafetyFlag> PendingTaskSafetyFlag::CreateInternal(
bool alive) {
// Explicit new, to access private constructor.
return rtc::scoped_refptr<PendingTaskSafetyFlag>(
new PendingTaskSafetyFlag(alive));
}
// static
rtc::scoped_refptr<PendingTaskSafetyFlag> PendingTaskSafetyFlag::Create() {
return CreateInternal(true);
}
rtc::scoped_refptr<PendingTaskSafetyFlag>
PendingTaskSafetyFlag::CreateDetached() {
rtc::scoped_refptr<PendingTaskSafetyFlag> safety_flag = CreateInternal(true);
safety_flag->main_sequence_.Detach();
return safety_flag;
}
// Creates a flag, but with its SequenceChecker explicitly initialized for
// a given task queue and the `alive()` flag specified.
rtc::scoped_refptr<PendingTaskSafetyFlag>
PendingTaskSafetyFlag::CreateAttachedToTaskQueue(
bool alive,
absl::Nonnull<TaskQueueBase*> attached_queue) {
RTC_DCHECK(attached_queue) << "Null TaskQueue provided";
return rtc::scoped_refptr<PendingTaskSafetyFlag>(
new PendingTaskSafetyFlag(alive, attached_queue));
}
rtc::scoped_refptr<PendingTaskSafetyFlag>
PendingTaskSafetyFlag::CreateDetachedInactive() {
rtc::scoped_refptr<PendingTaskSafetyFlag> safety_flag = CreateInternal(false);
safety_flag->main_sequence_.Detach();
return safety_flag;
}
void PendingTaskSafetyFlag::SetNotAlive() {
RTC_DCHECK_RUN_ON(&main_sequence_);
alive_ = false;
}
void PendingTaskSafetyFlag::SetAlive() {
RTC_DCHECK_RUN_ON(&main_sequence_);
alive_ = true;
}
bool PendingTaskSafetyFlag::alive() const {
RTC_DCHECK_RUN_ON(&main_sequence_);
return alive_;
}
} // namespace webrtc

View file

@ -0,0 +1,179 @@
/*
* Copyright 2020 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.
*/
#ifndef API_TASK_QUEUE_PENDING_TASK_SAFETY_FLAG_H_
#define API_TASK_QUEUE_PENDING_TASK_SAFETY_FLAG_H_
#include <utility>
#include "absl/base/nullability.h"
#include "absl/functional/any_invocable.h"
#include "api/ref_counted_base.h"
#include "api/scoped_refptr.h"
#include "api/sequence_checker.h"
#include "rtc_base/checks.h"
#include "rtc_base/system/no_unique_address.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
// The PendingTaskSafetyFlag and the ScopedTaskSafety are designed to address
// the issue where you have a task to be executed later that has references,
// but cannot guarantee that the referenced object is alive when the task is
// executed.
// This mechanism can be used with tasks that are created and destroyed
// on a single thread / task queue, and with tasks posted to the same
// thread/task queue, but tasks can be posted from any thread/TQ.
// Typical usage:
// When posting a task, post a copy (capture by-value in a lambda) of the flag
// reference and before performing the work, check the `alive()` state. Abort if
// alive() returns `false`:
//
// class ExampleClass {
// ....
// rtc::scoped_refptr<PendingTaskSafetyFlag> flag = safety_flag_;
// my_task_queue_->PostTask(
// [flag = std::move(flag), this] {
// // Now running on the main thread.
// if (!flag->alive())
// return;
// MyMethod();
// });
// ....
// ~ExampleClass() {
// safety_flag_->SetNotAlive();
// }
// scoped_refptr<PendingTaskSafetyFlag> safety_flag_
// = PendingTaskSafetyFlag::Create();
// }
//
// SafeTask makes this check automatic:
//
// my_task_queue_->PostTask(SafeTask(safety_flag_, [this] { MyMethod(); }));
//
class RTC_EXPORT PendingTaskSafetyFlag final
: public rtc::RefCountedNonVirtual<PendingTaskSafetyFlag> {
public:
static rtc::scoped_refptr<PendingTaskSafetyFlag> Create();
// Creates a flag, but with its SequenceChecker initially detached. Hence, it
// may be created on a different thread than the flag will be used on.
static rtc::scoped_refptr<PendingTaskSafetyFlag> CreateDetached();
// Creates a flag, but with its SequenceChecker explicitly initialized for
// a given task queue and the `alive()` flag specified.
static rtc::scoped_refptr<PendingTaskSafetyFlag> CreateAttachedToTaskQueue(
bool alive,
absl::Nonnull<TaskQueueBase*> attached_queue);
// Same as `CreateDetached()` except the initial state of the returned flag
// will be `!alive()`.
static rtc::scoped_refptr<PendingTaskSafetyFlag> CreateDetachedInactive();
~PendingTaskSafetyFlag() = default;
void SetNotAlive();
// The SetAlive method is intended to support Start/Stop/Restart usecases.
// When a class has called SetNotAlive on a flag used for posted tasks, and
// decides it wants to post new tasks and have them run, there are two
// reasonable ways to do that:
//
// (i) Use the below SetAlive method. One subtlety is that any task posted
// prior to SetNotAlive, and still in the queue, is resurrected and will
// run.
//
// (ii) Create a fresh flag, and just drop the reference to the old one. This
// avoids the above problem, and ensures that tasks poster prior to
// SetNotAlive stay cancelled. Instead, there's a potential data race on
// the flag pointer itself. Some synchronization is required between the
// thread overwriting the flag pointer, and the threads that want to post
// tasks and therefore read that same pointer.
void SetAlive();
bool alive() const;
protected:
explicit PendingTaskSafetyFlag(bool alive) : alive_(alive) {}
PendingTaskSafetyFlag(bool alive,
absl::Nonnull<TaskQueueBase*> attached_queue)
: alive_(alive), main_sequence_(attached_queue) {}
private:
static rtc::scoped_refptr<PendingTaskSafetyFlag> CreateInternal(bool alive);
bool alive_ = true;
RTC_NO_UNIQUE_ADDRESS SequenceChecker main_sequence_;
};
// The ScopedTaskSafety makes using PendingTaskSafetyFlag very simple.
// It does automatic PTSF creation and signalling of destruction when the
// ScopedTaskSafety instance goes out of scope.
//
// Example usage:
//
// my_task_queue->PostTask(SafeTask(scoped_task_safety.flag(),
// [this] {
// // task goes here
// }
//
// This should be used by the class that wants tasks dropped after destruction.
// The requirement is that the instance has to be constructed and destructed on
// the same thread as the potentially dropped tasks would be running on.
class RTC_EXPORT ScopedTaskSafety final {
public:
ScopedTaskSafety() = default;
explicit ScopedTaskSafety(rtc::scoped_refptr<PendingTaskSafetyFlag> flag)
: flag_(std::move(flag)) {}
~ScopedTaskSafety() { flag_->SetNotAlive(); }
// Returns a new reference to the safety flag.
rtc::scoped_refptr<PendingTaskSafetyFlag> flag() const { return flag_; }
// Marks the current flag as not-alive and attaches to a new one.
void reset(rtc::scoped_refptr<PendingTaskSafetyFlag> new_flag =
PendingTaskSafetyFlag::Create()) {
flag_->SetNotAlive();
flag_ = std::move(new_flag);
}
private:
rtc::scoped_refptr<PendingTaskSafetyFlag> flag_ =
PendingTaskSafetyFlag::Create();
};
// Like ScopedTaskSafety, but allows construction on a different thread than
// where the flag will be used.
class RTC_EXPORT ScopedTaskSafetyDetached final {
public:
ScopedTaskSafetyDetached() = default;
~ScopedTaskSafetyDetached() { flag_->SetNotAlive(); }
// Returns a new reference to the safety flag.
rtc::scoped_refptr<PendingTaskSafetyFlag> flag() const { return flag_; }
private:
rtc::scoped_refptr<PendingTaskSafetyFlag> flag_ =
PendingTaskSafetyFlag::CreateDetached();
};
inline absl::AnyInvocable<void() &&> SafeTask(
rtc::scoped_refptr<PendingTaskSafetyFlag> flag,
absl::AnyInvocable<void() &&> task) {
return [flag = std::move(flag), task = std::move(task)]() mutable {
if (flag->alive()) {
std::move(task)();
}
};
}
} // namespace webrtc
#endif // API_TASK_QUEUE_PENDING_TASK_SAFETY_FLAG_H_

View file

@ -0,0 +1,199 @@
/*
* 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 <memory>
#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<PendingTaskSafetyFlag> safety_flag;
{
// Scope for the `owner` instance.
class Owner {
public:
Owner() = default;
~Owner() { flag_->SetNotAlive(); }
rtc::scoped_refptr<PendingTaskSafetyFlag> 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<PendingTaskSafetyFlag> 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<PendingTaskSafetyFlag> 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<PendingTaskSafetyFlag> flag_ =
PendingTaskSafetyFlag::Create();
};
std::unique_ptr<Owner> owner;
tq1.SendTask([&owner]() {
owner = std::make_unique<Owner>();
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> owner;
bool stuff_done = false;
tq1.SendTask([&owner, &stuff_done]() {
owner = std::make_unique<Owner>(&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, PendingTaskInitializedForTaskQueue) {
TaskQueueForTest tq("PendingTaskAliveInitializedForTaskQueue");
// Create a new flag that initially `alive`, attached to a specific TQ.
auto flag = PendingTaskSafetyFlag::CreateAttachedToTaskQueue(true, tq.Get());
tq.SendTask([&flag]() { EXPECT_TRUE(flag->alive()); });
// Repeat the same steps but initialize as inactive.
flag = PendingTaskSafetyFlag::CreateAttachedToTaskQueue(false, tq.Get());
tq.SendTask([&flag]() { EXPECT_FALSE(flag->alive()); });
}
TEST(PendingTaskSafetyFlagTest, SafeTask) {
rtc::scoped_refptr<PendingTaskSafetyFlag> 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

View file

@ -0,0 +1,81 @@
/*
* 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/task_queue_base.h"
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/functional/any_invocable.h"
#include "api/units/time_delta.h"
#include "rtc_base/checks.h"
#if defined(ABSL_HAVE_THREAD_LOCAL)
namespace webrtc {
namespace {
ABSL_CONST_INIT thread_local TaskQueueBase* current = nullptr;
} // namespace
TaskQueueBase* TaskQueueBase::Current() {
return current;
}
TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter(
TaskQueueBase* task_queue)
: previous_(current) {
current = task_queue;
}
TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() {
current = previous_;
}
} // namespace webrtc
#elif defined(WEBRTC_POSIX)
#include <pthread.h>
namespace webrtc {
namespace {
ABSL_CONST_INIT pthread_key_t g_queue_ptr_tls = 0;
void InitializeTls() {
RTC_CHECK(pthread_key_create(&g_queue_ptr_tls, nullptr) == 0);
}
pthread_key_t GetQueuePtrTls() {
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
RTC_CHECK(pthread_once(&init_once, &InitializeTls) == 0);
return g_queue_ptr_tls;
}
} // namespace
TaskQueueBase* TaskQueueBase::Current() {
return static_cast<TaskQueueBase*>(pthread_getspecific(GetQueuePtrTls()));
}
TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter(
TaskQueueBase* task_queue)
: previous_(TaskQueueBase::Current()) {
pthread_setspecific(GetQueuePtrTls(), task_queue);
}
TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() {
pthread_setspecific(GetQueuePtrTls(), previous_);
}
} // namespace webrtc
#else
#error Unsupported platform
#endif

View file

@ -0,0 +1,198 @@
/*
* 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.
*/
#ifndef API_TASK_QUEUE_TASK_QUEUE_BASE_H_
#define API_TASK_QUEUE_TASK_QUEUE_BASE_H_
#include <memory>
#include <utility>
#include "absl/functional/any_invocable.h"
#include "api/location.h"
#include "api/units/time_delta.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
// Asynchronously executes tasks in a way that guarantees that they're executed
// in FIFO order and that tasks never overlap. Tasks may always execute on the
// same worker thread and they may not. To DCHECK that tasks are executing on a
// known task queue, use IsCurrent().
class RTC_LOCKABLE RTC_EXPORT TaskQueueBase {
public:
enum class DelayPrecision {
// This may include up to a 17 ms leeway in addition to OS timer precision.
// See PostDelayedTask() for more information.
kLow,
// This does not have the additional delay that kLow has, but it is still
// limited by OS timer precision. See PostDelayedHighPrecisionTask() for
// more information.
kHigh,
};
// Starts destruction of the task queue.
// On return ensures no task are running and no new tasks are able to start
// on the task queue.
// Responsible for deallocation. Deallocation may happen synchronously during
// Delete or asynchronously after Delete returns.
// Code not running on the TaskQueue should not make any assumption when
// TaskQueue is deallocated and thus should not call any methods after Delete.
// Code running on the TaskQueue should not call Delete, but can assume
// TaskQueue still exists and may call other methods, e.g. PostTask.
// Should be called on the same task queue or thread that this task queue
// was created on.
virtual void Delete() = 0;
// Schedules a `task` to execute. Tasks are executed in FIFO order.
// When a TaskQueue is deleted, pending tasks will not be executed but they
// will be deleted.
//
// As long as tasks are not posted from task destruction, posted tasks are
// guaranteed to be destroyed with Current() pointing to the task queue they
// were posted to, whether they're executed or not. That means SequenceChecker
// works during task destruction, a fact that can be used to guarantee
// thread-compatible object deletion happening on a particular task queue
// which can simplify class design.
// Note that this guarantee does not apply to delayed tasks.
//
// May be called on any thread or task queue, including this task queue.
void PostTask(absl::AnyInvocable<void() &&> task,
const Location& location = Location::Current()) {
PostTaskImpl(std::move(task), PostTaskTraits{}, location);
}
// Prefer PostDelayedTask() over PostDelayedHighPrecisionTask() whenever
// possible.
//
// Schedules a `task` to execute a specified `delay` from when the call is
// made, using "low" precision. All scheduling is affected by OS-specific
// leeway and current workloads which means that in terms of precision there
// are no hard guarantees, but in addition to the OS induced leeway, "low"
// precision adds up to a 17 ms additional leeway. The purpose of this leeway
// is to achieve more efficient CPU scheduling and reduce Idle Wake Up
// frequency.
//
// The task may execute with [-1, 17 + OS induced leeway) ms additional delay.
//
// Avoid making assumptions about the precision of the OS scheduler. On macOS,
// the OS induced leeway may be 10% of sleep interval. On Windows, 1 ms
// precision timers may be used but there are cases, such as when running on
// battery, when the timer precision can be as poor as 15 ms.
//
// "Low" precision is not implemented everywhere yet. Where not yet
// implemented, PostDelayedTask() has "high" precision. See
// https://crbug.com/webrtc/13583 for more information.
//
// May be called on any thread or task queue, including this task queue.
void PostDelayedTask(absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const Location& location = Location::Current()) {
PostDelayedTaskImpl(std::move(task), delay, PostDelayedTaskTraits{},
location);
}
// Prefer PostDelayedTask() over PostDelayedHighPrecisionTask() whenever
// possible.
//
// Schedules a `task` to execute a specified `delay` from when the call is
// made, using "high" precision. All scheduling is affected by OS-specific
// leeway and current workloads which means that in terms of precision there
// are no hard guarantees.
//
// The task may execute with [-1, OS induced leeway] ms additional delay.
//
// Avoid making assumptions about the precision of the OS scheduler. On macOS,
// the OS induced leeway may be 10% of sleep interval. On Windows, 1 ms
// precision timers may be used but there are cases, such as when running on
// battery, when the timer precision can be as poor as 15 ms.
//
// May be called on any thread or task queue, including this task queue.
void PostDelayedHighPrecisionTask(
absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const Location& location = Location::Current()) {
PostDelayedTaskTraits traits;
traits.high_precision = true;
PostDelayedTaskImpl(std::move(task), delay, traits, location);
}
// As specified by `precision`, calls either PostDelayedTask() or
// PostDelayedHighPrecisionTask().
void PostDelayedTaskWithPrecision(
DelayPrecision precision,
absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const Location& location = Location::Current()) {
switch (precision) {
case DelayPrecision::kLow:
PostDelayedTask(std::move(task), delay, location);
break;
case DelayPrecision::kHigh:
PostDelayedHighPrecisionTask(std::move(task), delay, location);
break;
}
}
// Returns the task queue that is running the current thread.
// Returns nullptr if this thread is not associated with any task queue.
// May be called on any thread or task queue, including this task queue.
static TaskQueueBase* Current();
bool IsCurrent() const { return Current() == this; }
protected:
// This is currently only present here to simplify introduction of future
// planned task queue changes.
struct PostTaskTraits {};
struct PostDelayedTaskTraits {
// If `high_precision` is false, tasks may execute within up to a 17 ms
// leeway in addition to OS timer precision. Otherwise the task should be
// limited to OS timer precision. See PostDelayedTask() and
// PostDelayedHighPrecisionTask() for more information.
bool high_precision = false;
};
class RTC_EXPORT CurrentTaskQueueSetter {
public:
explicit CurrentTaskQueueSetter(TaskQueueBase* task_queue);
CurrentTaskQueueSetter(const CurrentTaskQueueSetter&) = delete;
CurrentTaskQueueSetter& operator=(const CurrentTaskQueueSetter&) = delete;
~CurrentTaskQueueSetter();
private:
TaskQueueBase* const previous_;
};
// Subclasses should implement this method to support the behavior defined in
// the PostTask and PostTaskTraits docs above.
virtual void PostTaskImpl(absl::AnyInvocable<void() &&> task,
const PostTaskTraits& traits,
const Location& location) = 0;
// Subclasses should implement this method to support the behavior defined in
// the PostDelayedTask/PostHighPrecisionDelayedTask and PostDelayedTaskTraits
// docs above.
virtual void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const PostDelayedTaskTraits& traits,
const Location& location) = 0;
// Users of the TaskQueue should call Delete instead of directly deleting
// this object.
virtual ~TaskQueueBase() = default;
};
struct TaskQueueDeleter {
void operator()(TaskQueueBase* task_queue) const { task_queue->Delete(); }
};
} // namespace webrtc
#endif // API_TASK_QUEUE_TASK_QUEUE_BASE_H_

View file

@ -0,0 +1,35 @@
/*
* 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.
*/
#ifndef API_TASK_QUEUE_TASK_QUEUE_FACTORY_H_
#define API_TASK_QUEUE_TASK_QUEUE_FACTORY_H_
#include <memory>
#include "absl/strings/string_view.h"
#include "api/task_queue/task_queue_base.h"
namespace webrtc {
// The implementation of this interface must be thread-safe.
class TaskQueueFactory {
public:
// TaskQueue priority levels. On some platforms these will map to thread
// priorities, on others such as Mac and iOS, GCD queue priorities.
enum class Priority { NORMAL = 0, HIGH, LOW };
virtual ~TaskQueueFactory() = default;
virtual std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
absl::string_view name,
Priority priority) const = 0;
};
} // namespace webrtc
#endif // API_TASK_QUEUE_TASK_QUEUE_FACTORY_H_

View file

@ -0,0 +1,354 @@
/*
* 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/task_queue_test.h"
#include <memory>
#include "absl/cleanup/cleanup.h"
#include "absl/strings/string_view.h"
#include "api/task_queue/task_queue_base.h"
#include "api/units/time_delta.h"
#include "rtc_base/event.h"
#include "rtc_base/ref_counter.h"
#include "rtc_base/time_utils.h"
namespace webrtc {
namespace {
// Avoids a dependency to system_wrappers.
void SleepFor(TimeDelta duration) {
rtc::ScopedAllowBaseSyncPrimitivesForTesting allow;
rtc::Event event;
event.Wait(duration);
}
std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
const std::unique_ptr<webrtc::TaskQueueFactory>& factory,
absl::string_view task_queue_name,
TaskQueueFactory::Priority priority = TaskQueueFactory::Priority::NORMAL) {
return factory->CreateTaskQueue(task_queue_name, priority);
}
TEST_P(TaskQueueTest, Construct) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
auto queue = CreateTaskQueue(factory, "Construct");
EXPECT_FALSE(queue->IsCurrent());
}
TEST_P(TaskQueueTest, PostAndCheckCurrent) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
rtc::Event event;
auto queue = CreateTaskQueue(factory, "PostAndCheckCurrent");
// We're not running a task, so `queue` shouldn't be current.
// Note that because rtc::Thread also supports the TQ interface and
// TestMainImpl::Init wraps the main test thread (bugs.webrtc.org/9714), that
// means that TaskQueueBase::Current() will still return a valid value.
EXPECT_FALSE(queue->IsCurrent());
queue->PostTask([&event, &queue] {
EXPECT_TRUE(queue->IsCurrent());
event.Set();
});
EXPECT_TRUE(event.Wait(TimeDelta::Seconds(1)));
}
TEST_P(TaskQueueTest, PostCustomTask) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
rtc::Event ran;
auto queue = CreateTaskQueue(factory, "PostCustomImplementation");
class CustomTask {
public:
explicit CustomTask(rtc::Event* ran) : ran_(ran) {}
void operator()() { ran_->Set(); }
private:
rtc::Event* const ran_;
} my_task(&ran);
queue->PostTask(my_task);
EXPECT_TRUE(ran.Wait(TimeDelta::Seconds(1)));
}
TEST_P(TaskQueueTest, PostDelayedZero) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
rtc::Event event;
auto queue = CreateTaskQueue(factory, "PostDelayedZero");
queue->PostDelayedTask([&event] { event.Set(); }, TimeDelta::Zero());
EXPECT_TRUE(event.Wait(TimeDelta::Seconds(1)));
}
TEST_P(TaskQueueTest, PostFromQueue) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
rtc::Event event;
auto queue = CreateTaskQueue(factory, "PostFromQueue");
queue->PostTask(
[&event, &queue] { queue->PostTask([&event] { event.Set(); }); });
EXPECT_TRUE(event.Wait(TimeDelta::Seconds(1)));
}
TEST_P(TaskQueueTest, PostDelayed) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
rtc::Event event;
auto queue =
CreateTaskQueue(factory, "PostDelayed", TaskQueueFactory::Priority::HIGH);
int64_t start = rtc::TimeMillis();
queue->PostDelayedTask(
[&event, &queue] {
EXPECT_TRUE(queue->IsCurrent());
event.Set();
},
TimeDelta::Millis(100));
EXPECT_TRUE(event.Wait(TimeDelta::Seconds(1)));
int64_t end = rtc::TimeMillis();
// These tests are a little relaxed due to how "powerful" our test bots can
// be. Most recently we've seen windows bots fire the callback after 94-99ms,
// which is why we have a little bit of leeway backwards as well.
EXPECT_GE(end - start, 90u);
EXPECT_NEAR(end - start, 190u, 100u); // Accept 90-290.
}
TEST_P(TaskQueueTest, PostMultipleDelayed) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
auto queue = CreateTaskQueue(factory, "PostMultipleDelayed");
std::vector<rtc::Event> events(100);
for (int i = 0; i < 100; ++i) {
rtc::Event* event = &events[i];
queue->PostDelayedTask(
[event, &queue] {
EXPECT_TRUE(queue->IsCurrent());
event->Set();
},
TimeDelta::Millis(i));
}
for (rtc::Event& e : events)
EXPECT_TRUE(e.Wait(TimeDelta::Seconds(1)));
}
TEST_P(TaskQueueTest, PostDelayedAfterDestruct) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
rtc::Event run;
rtc::Event deleted;
auto queue = CreateTaskQueue(factory, "PostDelayedAfterDestruct");
absl::Cleanup cleanup = [&deleted] { deleted.Set(); };
queue->PostDelayedTask([&run, cleanup = std::move(cleanup)] { run.Set(); },
TimeDelta::Millis(100));
// Destroy the queue.
queue = nullptr;
// Task might outlive the TaskQueue, but still should be deleted.
EXPECT_TRUE(deleted.Wait(TimeDelta::Seconds(1)));
EXPECT_FALSE(run.Wait(TimeDelta::Zero())); // and should not run.
}
TEST_P(TaskQueueTest, PostDelayedHighPrecisionAfterDestruct) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
rtc::Event run;
rtc::Event deleted;
auto queue =
CreateTaskQueue(factory, "PostDelayedHighPrecisionAfterDestruct");
absl::Cleanup cleanup = [&deleted] { deleted.Set(); };
queue->PostDelayedHighPrecisionTask(
[&run, cleanup = std::move(cleanup)] { run.Set(); },
TimeDelta::Millis(100));
// Destroy the queue.
queue = nullptr;
// Task might outlive the TaskQueue, but still should be deleted.
EXPECT_TRUE(deleted.Wait(TimeDelta::Seconds(1)));
EXPECT_FALSE(run.Wait(TimeDelta::Zero())); // and should not run.
}
TEST_P(TaskQueueTest, PostedUnexecutedClosureDestroyedOnTaskQueue) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
auto queue =
CreateTaskQueue(factory, "PostedUnexecutedClosureDestroyedOnTaskQueue");
TaskQueueBase* queue_ptr = queue.get();
queue->PostTask([] { SleepFor(TimeDelta::Millis(100)); });
// Give the task queue a chance to start executing the first lambda.
SleepFor(TimeDelta::Millis(10));
rtc::Event finished;
// Then ensure the next lambda (which is likely not executing yet) is
// destroyed in the task queue context when the queue is deleted.
auto cleanup = absl::Cleanup([queue_ptr, &finished] {
EXPECT_EQ(queue_ptr, TaskQueueBase::Current());
finished.Set();
});
queue->PostTask([cleanup = std::move(cleanup)] {});
queue = nullptr;
finished.Wait(TimeDelta::Seconds(1));
}
TEST_P(TaskQueueTest, PostedClosureDestroyedOnTaskQueue) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
auto queue = CreateTaskQueue(factory, "PostedClosureDestroyedOnTaskQueue");
TaskQueueBase* queue_ptr = queue.get();
rtc::Event finished;
auto cleanup = absl::Cleanup([queue_ptr, &finished] {
EXPECT_EQ(queue_ptr, TaskQueueBase::Current());
finished.Set();
});
// The cleanup task may or may not have had time to execute when the task
// queue is destroyed. Regardless, the task should be destroyed on the
// queue.
queue->PostTask([cleanup = std::move(cleanup)] {});
queue = nullptr;
finished.Wait(TimeDelta::Seconds(1));
}
TEST_P(TaskQueueTest, PostedExecutedClosureDestroyedOnTaskQueue) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
auto queue =
CreateTaskQueue(factory, "PostedExecutedClosureDestroyedOnTaskQueue");
TaskQueueBase* queue_ptr = queue.get();
// Ensure an executed lambda is destroyed on the task queue.
rtc::Event finished;
queue->PostTask([cleanup = absl::Cleanup([queue_ptr, &finished] {
EXPECT_EQ(queue_ptr, TaskQueueBase::Current());
finished.Set();
})] {});
finished.Wait(TimeDelta::Seconds(1));
}
TEST_P(TaskQueueTest, PostAndReuse) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
rtc::Event event;
auto post_queue = CreateTaskQueue(factory, "PostQueue");
auto reply_queue = CreateTaskQueue(factory, "ReplyQueue");
int call_count = 0;
class ReusedTask {
public:
ReusedTask(int* counter, TaskQueueBase* reply_queue, rtc::Event* event)
: counter_(*counter), reply_queue_(reply_queue), event_(*event) {
EXPECT_EQ(counter_, 0);
}
ReusedTask(ReusedTask&&) = default;
ReusedTask& operator=(ReusedTask&&) = delete;
void operator()() && {
if (++counter_ == 1) {
reply_queue_->PostTask(std::move(*this));
// At this point, the object is in the moved-from state.
} else {
EXPECT_EQ(counter_, 2);
EXPECT_TRUE(reply_queue_->IsCurrent());
event_.Set();
}
}
private:
int& counter_;
TaskQueueBase* const reply_queue_;
rtc::Event& event_;
};
ReusedTask task(&call_count, reply_queue.get(), &event);
post_queue->PostTask(std::move(task));
EXPECT_TRUE(event.Wait(TimeDelta::Seconds(1)));
}
TEST_P(TaskQueueTest, PostALot) {
// Waits until DecrementCount called `count` times. Thread safe.
class BlockingCounter {
public:
explicit BlockingCounter(int initial_count) : count_(initial_count) {}
void DecrementCount() {
if (count_.DecRef() == webrtc::RefCountReleaseStatus::kDroppedLastRef) {
event_.Set();
}
}
bool Wait(TimeDelta give_up_after) { return event_.Wait(give_up_after); }
private:
webrtc_impl::RefCounter count_;
rtc::Event event_;
};
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
static constexpr int kTaskCount = 0xffff;
rtc::Event posting_done;
BlockingCounter all_destroyed(kTaskCount);
int tasks_executed = 0;
auto task_queue = CreateTaskQueue(factory, "PostALot");
task_queue->PostTask([&] {
// Post tasks from the queue to guarantee that the 1st task won't be
// executed before the last one is posted.
for (int i = 0; i < kTaskCount; ++i) {
absl::Cleanup cleanup = [&] { all_destroyed.DecrementCount(); };
task_queue->PostTask([&tasks_executed, cleanup = std::move(cleanup)] {
++tasks_executed;
});
}
posting_done.Set();
});
// Before destroying the task queue wait until all child tasks are posted.
posting_done.Wait(rtc::Event::kForever);
// Destroy the task queue.
task_queue = nullptr;
// Expect all tasks are destroyed eventually. In some task queue
// implementations that might happen on a different thread after task queue is
// destroyed.
EXPECT_TRUE(all_destroyed.Wait(TimeDelta::Minutes(1)));
EXPECT_LE(tasks_executed, kTaskCount);
}
// Test posting two tasks that have shared state not protected by a
// lock. The TaskQueue should guarantee memory read-write order and
// FIFO task execution order, so the second task should always see the
// changes that were made by the first task.
//
// If the TaskQueue doesn't properly synchronize the execution of
// tasks, there will be a data race, which is undefined behavior. The
// EXPECT calls may randomly catch this, but to make the most of this
// unit test, run it under TSan or some other tool that is able to
// directly detect data races.
TEST_P(TaskQueueTest, PostTwoWithSharedUnprotectedState) {
std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(nullptr);
struct SharedState {
// First task will set this value to 1 and second will assert it.
int state = 0;
} state;
auto queue = CreateTaskQueue(factory, "PostTwoWithSharedUnprotectedState");
rtc::Event done;
queue->PostTask([&state, &queue, &done] {
// Post tasks from queue to guarantee, that 1st task won't be
// executed before the second one will be posted.
queue->PostTask([&state] { state.state = 1; });
queue->PostTask([&state, &done] {
EXPECT_EQ(state.state, 1);
done.Set();
});
// Check, that state changing tasks didn't start yet.
EXPECT_EQ(state.state, 0);
});
EXPECT_TRUE(done.Wait(TimeDelta::Seconds(1)));
}
// TaskQueueTest is a set of tests for any implementation of the TaskQueueBase.
// Tests are instantiated next to the concrete implementation(s).
// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#creating-value-parameterized-abstract-tests
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TaskQueueTest);
} // namespace
} // namespace webrtc

View file

@ -0,0 +1,41 @@
/*
* 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.
*/
#ifndef API_TASK_QUEUE_TASK_QUEUE_TEST_H_
#define API_TASK_QUEUE_TASK_QUEUE_TEST_H_
#include <functional>
#include <memory>
#include "api/field_trials_view.h"
#include "api/task_queue/task_queue_factory.h"
#include "test/gtest.h"
namespace webrtc {
// Suite of tests to verify TaskQueue implementation with.
// Example usage:
//
// namespace {
//
// using ::testing::Values;
// using ::webrtc::TaskQueueTest;
//
// std::unique_ptr<webrtc::TaskQueueFactory> CreateMyFactory();
//
// INSTANTIATE_TEST_SUITE_P(My, TaskQueueTest, Values(CreateMyFactory));
//
// } // namespace
class TaskQueueTest
: public ::testing::TestWithParam<std::function<
std::unique_ptr<TaskQueueFactory>(const FieldTrialsView*)>> {};
} // namespace webrtc
#endif // API_TASK_QUEUE_TASK_QUEUE_TEST_H_

View file

@ -0,0 +1,20 @@
# Copyright (c) 2018 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.
import("../../../webrtc.gni")
rtc_library("mock_task_queue_base") {
testonly = true
sources = [ "mock_task_queue_base.h" ]
deps = [
"../../../api/task_queue:task_queue",
"../../../api/units:time_delta",
"../../../test:test_support",
]
absl_deps = [ "//third_party/abseil-cpp/absl/functional:any_invocable" ]
}

View file

@ -0,0 +1,44 @@
/*
* Copyright 2022 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.
*/
#ifndef API_TASK_QUEUE_TEST_MOCK_TASK_QUEUE_BASE_H_
#define API_TASK_QUEUE_TEST_MOCK_TASK_QUEUE_BASE_H_
#include "absl/functional/any_invocable.h"
#include "api/task_queue/task_queue_base.h"
#include "api/units/time_delta.h"
#include "test/gmock.h"
namespace webrtc {
class MockTaskQueueBase : public TaskQueueBase {
public:
using TaskQueueBase::PostDelayedTaskTraits;
using TaskQueueBase::PostTaskTraits;
MOCK_METHOD(void, Delete, (), (override));
MOCK_METHOD(void,
PostTaskImpl,
(absl::AnyInvocable<void() &&>,
const PostTaskTraits&,
const Location&),
(override));
MOCK_METHOD(void,
PostDelayedTaskImpl,
(absl::AnyInvocable<void() &&>,
TimeDelta,
const PostDelayedTaskTraits&,
const Location&),
(override));
};
} // namespace webrtc
#endif // API_TASK_QUEUE_TEST_MOCK_TASK_QUEUE_BASE_H_