summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/operations_chain.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/rtc_base/operations_chain.h
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/rtc_base/operations_chain.h')
-rw-r--r--third_party/libwebrtc/rtc_base/operations_chain.h203
1 files changed, 203 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/operations_chain.h b/third_party/libwebrtc/rtc_base/operations_chain.h
new file mode 100644
index 0000000000..0e8c0681ba
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/operations_chain.h
@@ -0,0 +1,203 @@
+/*
+ * 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 RTC_BASE_OPERATIONS_CHAIN_H_
+#define RTC_BASE_OPERATIONS_CHAIN_H_
+
+#include <functional>
+#include <memory>
+#include <queue>
+#include <set>
+#include <type_traits>
+#include <utility>
+
+#include "absl/types/optional.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/ref_count.h"
+#include "rtc_base/ref_counted_object.h"
+#include "rtc_base/system/no_unique_address.h"
+
+namespace rtc {
+
+namespace rtc_operations_chain_internal {
+
+// Abstract base class for operations on the OperationsChain. Run() must be
+// invoked exactly once during the Operation's lifespan.
+class Operation {
+ public:
+ virtual ~Operation() {}
+
+ virtual void Run() = 0;
+};
+
+// FunctorT is the same as in OperationsChain::ChainOperation(). `callback_` is
+// passed on to the `functor_` and is used to inform the OperationsChain that
+// the operation completed. The functor is responsible for invoking the
+// callback when the operation has completed.
+template <typename FunctorT>
+class OperationWithFunctor final : public Operation {
+ public:
+ OperationWithFunctor(FunctorT&& functor, std::function<void()> callback)
+ : functor_(std::forward<FunctorT>(functor)),
+ callback_(std::move(callback)) {}
+
+ ~OperationWithFunctor() override {
+#if RTC_DCHECK_IS_ON
+ RTC_DCHECK(has_run_);
+#endif // RTC_DCHECK_IS_ON
+ }
+
+ void Run() override {
+#if RTC_DCHECK_IS_ON
+ RTC_DCHECK(!has_run_);
+ has_run_ = true;
+#endif // RTC_DCHECK_IS_ON
+ // The functor being executed may invoke the callback synchronously,
+ // marking the operation as complete. As such, `this` OperationWithFunctor
+ // object may get deleted here, including destroying `functor_`. To
+ // protect the functor from self-destruction while running, it is moved to
+ // a local variable.
+ auto functor = std::move(functor_);
+ functor(std::move(callback_));
+ // `this` may now be deleted; don't touch any member variables.
+ }
+
+ private:
+ typename std::remove_reference<FunctorT>::type functor_;
+ std::function<void()> callback_;
+#if RTC_DCHECK_IS_ON
+ bool has_run_ = false;
+#endif // RTC_DCHECK_IS_ON
+};
+
+} // namespace rtc_operations_chain_internal
+
+// An implementation of an operations chain. An operations chain is used to
+// ensure that asynchronous tasks are executed in-order with at most one task
+// running at a time. The notion of an operation chain is defined in
+// https://w3c.github.io/webrtc-pc/#dfn-operations-chain, though unlike this
+// implementation, the referenced definition is coupled with a peer connection.
+//
+// An operation is an asynchronous task. The operation starts when its functor
+// is invoked, and completes when the callback that is passed to functor is
+// invoked by the operation. The operation must start and complete on the same
+// sequence that the operation was "chained" on. As such, the OperationsChain
+// operates in a "single-threaded" fashion, but the asynchronous operations may
+// use any number of threads to achieve "in parallel" behavior.
+//
+// When an operation is chained onto the OperationsChain, it is enqueued to be
+// executed. Operations are executed in FIFO order, where the next operation
+// does not start until the previous operation has completed. OperationsChain
+// guarantees that:
+// - If the operations chain is empty when an operation is chained, the
+// operation starts immediately, inside ChainOperation().
+// - If the operations chain is not empty when an operation is chained, the
+// operation starts upon the previous operation completing, inside the
+// callback.
+//
+// An operation is contractually obligated to invoke the completion callback
+// exactly once. Cancelling a chained operation is not supported by the
+// OperationsChain; an operation that wants to be cancellable is responsible for
+// aborting its own steps. The callback must still be invoked.
+//
+// The OperationsChain is kept-alive through reference counting if there are
+// operations pending. This, together with the contract, guarantees that all
+// operations that are chained get executed.
+class OperationsChain final : public RefCountedNonVirtual<OperationsChain> {
+ public:
+ static scoped_refptr<OperationsChain> Create();
+ ~OperationsChain();
+
+ OperationsChain(const OperationsChain&) = delete;
+ OperationsChain& operator=(const OperationsChain&) = delete;
+
+ void SetOnChainEmptyCallback(std::function<void()> on_chain_empty_callback);
+ bool IsEmpty() const;
+
+ // Chains an operation. Chained operations are executed in FIFO order. The
+ // operation starts when `functor` is executed by the OperationsChain and is
+ // contractually obligated to invoke the callback passed to it when the
+ // operation is complete. Operations must start and complete on the same
+ // sequence that this method was invoked on.
+ //
+ // If the OperationsChain is empty, the operation starts immediately.
+ // Otherwise it starts upon the previous operation completing.
+ //
+ // Requirements of FunctorT:
+ // - FunctorT is movable.
+ // - FunctorT implements "T operator()(std::function<void()> callback)" or
+ // "T operator()(std::function<void()> callback) const" for some T (if T is
+ // not void, the return value is discarded in the invoking sequence). The
+ // operator starts the operation; when the operation is complete, "callback"
+ // MUST be invoked, and it MUST be so on the sequence that ChainOperation()
+ // was invoked on.
+ //
+ // Lambda expressions are valid functors.
+ template <typename FunctorT>
+ void ChainOperation(FunctorT&& functor) {
+ RTC_DCHECK_RUN_ON(&sequence_checker_);
+ chained_operations_.push(
+ std::make_unique<
+ rtc_operations_chain_internal::OperationWithFunctor<FunctorT>>(
+ std::forward<FunctorT>(functor), CreateOperationsChainCallback()));
+ // If this is the only operation in the chain we execute it immediately.
+ // Otherwise the callback will get invoked when the pending operation
+ // completes which will trigger the next operation to execute.
+ if (chained_operations_.size() == 1) {
+ chained_operations_.front()->Run();
+ }
+ }
+
+ private:
+ friend class CallbackHandle;
+
+ // The callback that is passed to an operation's functor (that is used to
+ // inform the OperationsChain that the operation has completed) is of type
+ // std::function<void()>, which is a copyable type. To allow the callback to
+ // be copyable, it is backed up by this reference counted handle. See
+ // CreateOperationsChainCallback().
+ class CallbackHandle final : public RefCountedNonVirtual<CallbackHandle> {
+ public:
+ explicit CallbackHandle(scoped_refptr<OperationsChain> operations_chain);
+ ~CallbackHandle();
+
+ CallbackHandle(const CallbackHandle&) = delete;
+ CallbackHandle& operator=(const CallbackHandle&) = delete;
+
+ void OnOperationComplete();
+
+ private:
+ scoped_refptr<OperationsChain> operations_chain_;
+#if RTC_DCHECK_IS_ON
+ bool has_run_ = false;
+#endif // RTC_DCHECK_IS_ON
+ };
+
+ OperationsChain();
+
+ std::function<void()> CreateOperationsChainCallback();
+ void OnOperationComplete();
+
+ RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_;
+ // FIFO-list of operations that are chained. An operation that is executing
+ // remains on this list until it has completed by invoking the callback passed
+ // to it.
+ std::queue<std::unique_ptr<rtc_operations_chain_internal::Operation>>
+ chained_operations_ RTC_GUARDED_BY(sequence_checker_);
+ absl::optional<std::function<void()>> on_chain_empty_callback_
+ RTC_GUARDED_BY(sequence_checker_);
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_OPERATIONS_CHAIN_H_