Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
198
TMessagesProj/jni/voip/webrtc/api/task_queue/task_queue_base.h
Normal file
198
TMessagesProj/jni/voip/webrtc/api/task_queue/task_queue_base.h
Normal 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_
|
||||
|
|
@ -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_
|
||||
354
TMessagesProj/jni/voip/webrtc/api/task_queue/task_queue_test.cc
Normal file
354
TMessagesProj/jni/voip/webrtc/api/task_queue/task_queue_test.cc
Normal 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
|
||||
|
|
@ -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_
|
||||
20
TMessagesProj/jni/voip/webrtc/api/task_queue/test/BUILD.gn
Normal file
20
TMessagesProj/jni/voip/webrtc/api/task_queue/test/BUILD.gn
Normal 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" ]
|
||||
}
|
||||
|
|
@ -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_
|
||||
Loading…
Add table
Add a link
Reference in a new issue