summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/api/task_queue
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/libwebrtc/api/task_queue/BUILD.gn166
-rw-r--r--third_party/libwebrtc/api/task_queue/DEPS14
-rw-r--r--third_party/libwebrtc/api/task_queue/default_task_queue_factory.h25
-rw-r--r--third_party/libwebrtc/api/task_queue/default_task_queue_factory_gcd.cc23
-rw-r--r--third_party/libwebrtc/api/task_queue/default_task_queue_factory_libevent.cc23
-rw-r--r--third_party/libwebrtc/api/task_queue/default_task_queue_factory_stdlib.cc23
-rw-r--r--third_party/libwebrtc/api/task_queue/default_task_queue_factory_stdlib_or_libevent_experiment.cc38
-rw-r--r--third_party/libwebrtc/api/task_queue/default_task_queue_factory_unittest.cc24
-rw-r--r--third_party/libwebrtc/api/task_queue/default_task_queue_factory_win.cc23
-rw-r--r--third_party/libwebrtc/api/task_queue/pending_task_safety_flag.cc57
-rw-r--r--third_party/libwebrtc/api/task_queue/pending_task_safety_flag.h168
-rw-r--r--third_party/libwebrtc/api/task_queue/pending_task_safety_flag_gn/moz.build221
-rw-r--r--third_party/libwebrtc/api/task_queue/pending_task_safety_flag_unittest.cc188
-rw-r--r--third_party/libwebrtc/api/task_queue/task_queue_base.cc81
-rw-r--r--third_party/libwebrtc/api/task_queue/task_queue_base.h156
-rw-r--r--third_party/libwebrtc/api/task_queue/task_queue_factory.h35
-rw-r--r--third_party/libwebrtc/api/task_queue/task_queue_gn/moz.build221
-rw-r--r--third_party/libwebrtc/api/task_queue/task_queue_test.cc333
-rw-r--r--third_party/libwebrtc/api/task_queue/task_queue_test.h41
-rw-r--r--third_party/libwebrtc/api/task_queue/test/BUILD.gn20
-rw-r--r--third_party/libwebrtc/api/task_queue/test/mock_task_queue_base.h37
21 files changed, 1917 insertions, 0 deletions
diff --git a/third_party/libwebrtc/api/task_queue/BUILD.gn b/third_party/libwebrtc/api/task_queue/BUILD.gn
new file mode 100644
index 0000000000..1c342cb57e
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/BUILD.gn
@@ -0,0 +1,166 @@
+# 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("task_queue") {
+ visibility = [ "*" ]
+ public = [
+ "task_queue_base.h",
+ "task_queue_factory.h",
+ ]
+ sources = [ "task_queue_base.cc" ]
+
+ deps = [
+ "../../rtc_base:checks",
+ "../../rtc_base:macromagic",
+ "../../rtc_base/system:rtc_export",
+ "../units:time_delta",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/base:config",
+ "//third_party/abseil-cpp/absl/base:core_headers",
+ "//third_party/abseil-cpp/absl/functional:any_invocable",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+}
+
+# Mozilla - we want to ensure that rtc_include_tests is set to false
+# to guarantee that default_task_queue_factory is not used so we
+# know that remaining win32k code in task_queue_win.cc is not built.
+# See Bug 1797161 for more info.
+assert(!rtc_include_tests, "Mozilla - verify rtc_include_tests is off")
+if (rtc_include_tests) {
+rtc_library("task_queue_test") {
+ visibility = [ "*" ]
+ testonly = true
+ sources = [
+ "task_queue_test.cc",
+ "task_queue_test.h",
+ ]
+
+ check_includes = false # no-presubmit-check TODO(bugs.webrtc.org/9419)
+ if (build_with_chromium) {
+ visibility = []
+ visibility = webrtc_default_visibility
+ visibility += [
+ # This is the only Chromium targets that can depend on this. The reason
+ # behind this is the fact that these are 'testonly' targets and as such
+ # it cannot be part of the WebRTC component.
+ "//components/webrtc:unit_tests",
+ "//third_party/blink/renderer/platform:blink_platform_unittests_sources",
+ ]
+
+ # Don't depend on WebRTC code outside of webrtc_overrides:webrtc_component
+ # because this will break the WebRTC component build in Chromium.
+ deps = [
+ "../../../webrtc_overrides:webrtc_component",
+ "../../test:test_support",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/cleanup",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+ } else {
+ deps = [
+ ":default_task_queue_factory",
+ ":task_queue",
+ "../../api:field_trials_view",
+ "../../api:make_ref_counted",
+ "../../api/units:time_delta",
+ "../../rtc_base:refcount",
+ "../../rtc_base:rtc_event",
+ "../../rtc_base:timeutils",
+ "../../test:test_support",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/cleanup",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+ }
+}
+}
+
+rtc_library("default_task_queue_factory") {
+ visibility = [ "*" ]
+ if (!is_ios && !is_android) {
+ poisonous = [ "default_task_queue" ]
+ }
+ sources = [ "default_task_queue_factory.h" ]
+ deps = [
+ ":task_queue",
+ "../../api:field_trials_view",
+ "../../rtc_base/memory:always_valid_pointer",
+ ]
+
+ if (rtc_enable_libevent) {
+ if (is_android) {
+ sources +=
+ [ "default_task_queue_factory_stdlib_or_libevent_experiment.cc" ]
+ deps += [
+ "../../api/transport:field_trial_based_config",
+ "../../rtc_base:logging",
+ "../../rtc_base:rtc_task_queue_libevent",
+ "../../rtc_base:rtc_task_queue_stdlib",
+ ]
+ } else {
+ sources += [ "default_task_queue_factory_libevent.cc" ]
+ deps += [ "../../rtc_base:rtc_task_queue_libevent" ]
+ }
+ } else if (is_mac || is_ios) {
+ sources += [ "default_task_queue_factory_gcd.cc" ]
+ deps += [ "../../rtc_base:rtc_task_queue_gcd" ]
+ } else if (is_win && current_os != "winuwp") {
+ sources += [ "default_task_queue_factory_win.cc" ]
+ deps += [ "../../rtc_base:rtc_task_queue_win" ]
+ } else {
+ sources += [ "default_task_queue_factory_stdlib.cc" ]
+ deps += [ "../../rtc_base:rtc_task_queue_stdlib" ]
+ }
+}
+
+rtc_library("pending_task_safety_flag") {
+ visibility = [ "*" ]
+ sources = [
+ "pending_task_safety_flag.cc",
+ "pending_task_safety_flag.h",
+ ]
+ deps = [
+ "../../api:refcountedbase",
+ "../../api:scoped_refptr",
+ "../../api:sequence_checker",
+ "../../rtc_base:checks",
+ "../../rtc_base/system:no_unique_address",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/functional:any_invocable" ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("task_queue_default_factory_unittests") {
+ testonly = true
+ sources = [ "default_task_queue_factory_unittest.cc" ]
+ deps = [
+ ":default_task_queue_factory",
+ ":task_queue_test",
+ "../../test:test_support",
+ ]
+ }
+
+ rtc_library("pending_task_safety_flag_unittests") {
+ testonly = true
+ sources = [ "pending_task_safety_flag_unittest.cc" ]
+ deps = [
+ ":pending_task_safety_flag",
+ "../../rtc_base:logging",
+ "../../rtc_base:rtc_event",
+ "../../rtc_base:rtc_task_queue",
+ "../../rtc_base:task_queue_for_test",
+ "../../test:test_support",
+ ]
+ }
+}
diff --git a/third_party/libwebrtc/api/task_queue/DEPS b/third_party/libwebrtc/api/task_queue/DEPS
new file mode 100644
index 0000000000..1365edb504
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/DEPS
@@ -0,0 +1,14 @@
+specific_include_rules = {
+ "task_queue_base\.h": [
+ # Make TaskQueueBase RTC_LOCKABALE to allow annotate variables are only
+ # accessed on specific task queue.
+ "+rtc_base/thread_annotations.h",
+ ],
+ "task_queue_test\.h": [
+ "+test/gtest.h",
+ ],
+ "pending_task_safety_flag.h": [
+ "+rtc_base/checks.h",
+ "+rtc_base/system/no_unique_address.h",
+ ],
+}
diff --git a/third_party/libwebrtc/api/task_queue/default_task_queue_factory.h b/third_party/libwebrtc/api/task_queue/default_task_queue_factory.h
new file mode 100644
index 0000000000..1d2dbd7ec2
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/default_task_queue_factory.h
@@ -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_
diff --git a/third_party/libwebrtc/api/task_queue/default_task_queue_factory_gcd.cc b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_gcd.cc
new file mode 100644
index 0000000000..391f09b393
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_gcd.cc
@@ -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
diff --git a/third_party/libwebrtc/api/task_queue/default_task_queue_factory_libevent.cc b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_libevent.cc
new file mode 100644
index 0000000000..89079f51ca
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_libevent.cc
@@ -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
diff --git a/third_party/libwebrtc/api/task_queue/default_task_queue_factory_stdlib.cc b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_stdlib.cc
new file mode 100644
index 0000000000..10cda7c5ec
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_stdlib.cc
@@ -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
diff --git a/third_party/libwebrtc/api/task_queue/default_task_queue_factory_stdlib_or_libevent_experiment.cc b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_stdlib_or_libevent_experiment.cc
new file mode 100644
index 0000000000..dc6e835907
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_stdlib_or_libevent_experiment.cc
@@ -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
diff --git a/third_party/libwebrtc/api/task_queue/default_task_queue_factory_unittest.cc b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_unittest.cc
new file mode 100644
index 0000000000..92c17d8444
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_unittest.cc
@@ -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
diff --git a/third_party/libwebrtc/api/task_queue/default_task_queue_factory_win.cc b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_win.cc
new file mode 100644
index 0000000000..e3adc07327
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_win.cc
@@ -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
diff --git a/third_party/libwebrtc/api/task_queue/pending_task_safety_flag.cc b/third_party/libwebrtc/api/task_queue/pending_task_safety_flag.cc
new file mode 100644
index 0000000000..437ce0755d
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/pending_task_safety_flag.cc
@@ -0,0 +1,57 @@
+/*
+ * 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;
+}
+
+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
diff --git a/third_party/libwebrtc/api/task_queue/pending_task_safety_flag.h b/third_party/libwebrtc/api/task_queue/pending_task_safety_flag.h
new file mode 100644
index 0000000000..3b948ca8f1
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/pending_task_safety_flag.h
@@ -0,0 +1,168 @@
+/*
+ * 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/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"
+
+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 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();
+
+ // 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) {}
+
+ 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 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 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_
diff --git a/third_party/libwebrtc/api/task_queue/pending_task_safety_flag_gn/moz.build b/third_party/libwebrtc/api/task_queue/pending_task_safety_flag_gn/moz.build
new file mode 100644
index 0000000000..d7e6a087fa
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/pending_task_safety_flag_gn/moz.build
@@ -0,0 +1,221 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/api/task_queue/pending_task_safety_flag.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("pending_task_safety_flag_gn")
diff --git a/third_party/libwebrtc/api/task_queue/pending_task_safety_flag_unittest.cc b/third_party/libwebrtc/api/task_queue/pending_task_safety_flag_unittest.cc
new file mode 100644
index 0000000000..cedf0eb8df
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/pending_task_safety_flag_unittest.cc
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/task_queue/pending_task_safety_flag.h"
+
+#include <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, 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
diff --git a/third_party/libwebrtc/api/task_queue/task_queue_base.cc b/third_party/libwebrtc/api/task_queue/task_queue_base.cc
new file mode 100644
index 0000000000..ecdc7f7691
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/task_queue_base.cc
@@ -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
diff --git a/third_party/libwebrtc/api/task_queue/task_queue_base.h b/third_party/libwebrtc/api/task_queue/task_queue_base.h
new file mode 100644
index 0000000000..f78600de60
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/task_queue_base.h
@@ -0,0 +1,156 @@
+/*
+ * 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/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.
+ virtual void PostTask(absl::AnyInvocable<void() &&> task) = 0;
+
+ // 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.
+ virtual void PostDelayedTask(absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) = 0;
+
+ // 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.
+ virtual void PostDelayedHighPrecisionTask(absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) = 0;
+
+ // As specified by `precision`, calls either PostDelayedTask() or
+ // PostDelayedHighPrecisionTask().
+ void PostDelayedTaskWithPrecision(DelayPrecision precision,
+ absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) {
+ switch (precision) {
+ case DelayPrecision::kLow:
+ PostDelayedTask(std::move(task), delay);
+ break;
+ case DelayPrecision::kHigh:
+ PostDelayedHighPrecisionTask(std::move(task), delay);
+ 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:
+ class RTC_EXPORT CurrentTaskQueueSetter {
+ public:
+ explicit CurrentTaskQueueSetter(TaskQueueBase* task_queue);
+ CurrentTaskQueueSetter(const CurrentTaskQueueSetter&) = delete;
+ CurrentTaskQueueSetter& operator=(const CurrentTaskQueueSetter&) = delete;
+ ~CurrentTaskQueueSetter();
+
+ private:
+ TaskQueueBase* const previous_;
+ };
+
+ // 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_
diff --git a/third_party/libwebrtc/api/task_queue/task_queue_factory.h b/third_party/libwebrtc/api/task_queue/task_queue_factory.h
new file mode 100644
index 0000000000..b68ab33f69
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/task_queue_factory.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_
diff --git a/third_party/libwebrtc/api/task_queue/task_queue_gn/moz.build b/third_party/libwebrtc/api/task_queue/task_queue_gn/moz.build
new file mode 100644
index 0000000000..c4d9c9d67d
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/task_queue_gn/moz.build
@@ -0,0 +1,221 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/api/task_queue/task_queue_base.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("task_queue_gn")
diff --git a/third_party/libwebrtc/api/task_queue/task_queue_test.cc b/third_party/libwebrtc/api/task_queue/task_queue_test.cc
new file mode 100644
index 0000000000..7849f4273d
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/task_queue_test.cc
@@ -0,0 +1,333 @@
+/*
+ * 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));
+ // 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] { EXPECT_EQ(queue_ptr, TaskQueueBase::Current()); });
+ queue->PostTask([cleanup = std::move(cleanup)] {});
+ queue = nullptr;
+}
+
+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(rtc::Event::kForever);
+}
+
+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() == rtc::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
diff --git a/third_party/libwebrtc/api/task_queue/task_queue_test.h b/third_party/libwebrtc/api/task_queue/task_queue_test.h
new file mode 100644
index 0000000000..214f95008f
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/task_queue_test.h
@@ -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_
diff --git a/third_party/libwebrtc/api/task_queue/test/BUILD.gn b/third_party/libwebrtc/api/task_queue/test/BUILD.gn
new file mode 100644
index 0000000000..25f7ed0c7f
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/test/BUILD.gn
@@ -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" ]
+}
diff --git a/third_party/libwebrtc/api/task_queue/test/mock_task_queue_base.h b/third_party/libwebrtc/api/task_queue/test/mock_task_queue_base.h
new file mode 100644
index 0000000000..2e99be7e82
--- /dev/null
+++ b/third_party/libwebrtc/api/task_queue/test/mock_task_queue_base.h
@@ -0,0 +1,37 @@
+/*
+ * 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:
+ MOCK_METHOD(void, Delete, (), (override));
+ MOCK_METHOD(void, PostTask, (absl::AnyInvocable<void() &&>), (override));
+ MOCK_METHOD(void,
+ PostDelayedTask,
+ (absl::AnyInvocable<void() &&>, TimeDelta),
+ (override));
+ MOCK_METHOD(void,
+ PostDelayedHighPrecisionTask,
+ (absl::AnyInvocable<void() &&>, TimeDelta),
+ (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TASK_QUEUE_TEST_MOCK_TASK_QUEUE_BASE_H_