summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/net/dcsctp/timer/timer.h
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/net/dcsctp/timer/timer.h')
-rw-r--r--third_party/libwebrtc/net/dcsctp/timer/timer.h212
1 files changed, 212 insertions, 0 deletions
diff --git a/third_party/libwebrtc/net/dcsctp/timer/timer.h b/third_party/libwebrtc/net/dcsctp/timer/timer.h
new file mode 100644
index 0000000000..31b496dc81
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/timer/timer.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2021 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 NET_DCSCTP_TIMER_TIMER_H_
+#define NET_DCSCTP_TIMER_TIMER_H_
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/task_queue/task_queue_base.h"
+#include "net/dcsctp/public/timeout.h"
+#include "rtc_base/strong_alias.h"
+
+namespace dcsctp {
+
+using TimerID = webrtc::StrongAlias<class TimerIDTag, uint32_t>;
+using TimerGeneration = webrtc::StrongAlias<class TimerGenerationTag, uint32_t>;
+
+enum class TimerBackoffAlgorithm {
+ // The base duration will be used for any restart.
+ kFixed,
+ // An exponential backoff is used for restarts, with a 2x multiplier, meaning
+ // that every restart will use a duration that is twice as long as the
+ // previous.
+ kExponential,
+};
+
+struct TimerOptions {
+ explicit TimerOptions(DurationMs duration)
+ : TimerOptions(duration, TimerBackoffAlgorithm::kExponential) {}
+ TimerOptions(DurationMs duration, TimerBackoffAlgorithm backoff_algorithm)
+ : TimerOptions(duration, backoff_algorithm, absl::nullopt) {}
+ TimerOptions(DurationMs duration,
+ TimerBackoffAlgorithm backoff_algorithm,
+ absl::optional<int> max_restarts)
+ : TimerOptions(duration, backoff_algorithm, max_restarts, absl::nullopt) {
+ }
+ TimerOptions(DurationMs duration,
+ TimerBackoffAlgorithm backoff_algorithm,
+ absl::optional<int> max_restarts,
+ absl::optional<DurationMs> max_backoff_duration)
+ : TimerOptions(duration,
+ backoff_algorithm,
+ max_restarts,
+ max_backoff_duration,
+ webrtc::TaskQueueBase::DelayPrecision::kLow) {}
+ TimerOptions(DurationMs duration,
+ TimerBackoffAlgorithm backoff_algorithm,
+ absl::optional<int> max_restarts,
+ absl::optional<DurationMs> max_backoff_duration,
+ webrtc::TaskQueueBase::DelayPrecision precision)
+ : duration(duration),
+ backoff_algorithm(backoff_algorithm),
+ max_restarts(max_restarts),
+ max_backoff_duration(max_backoff_duration),
+ precision(precision) {}
+
+ // The initial timer duration. Can be overridden with `set_duration`.
+ const DurationMs duration;
+ // If the duration should be increased (using exponential backoff) when it is
+ // restarted. If not set, the same duration will be used.
+ const TimerBackoffAlgorithm backoff_algorithm;
+ // The maximum number of times that the timer will be automatically restarted,
+ // or absl::nullopt if there is no limit.
+ const absl::optional<int> max_restarts;
+ // The maximum timeout value for exponential backoff.
+ const absl::optional<DurationMs> max_backoff_duration;
+ // The precision of the webrtc::TaskQueueBase used for scheduling.
+ const webrtc::TaskQueueBase::DelayPrecision precision;
+};
+
+// A high-level timer (in contrast to the low-level `Timeout` class).
+//
+// Timers are started and can be stopped or restarted. When a timer expires,
+// the provided `on_expired` callback will be triggered. A timer is
+// automatically restarted, as long as the number of restarts is below the
+// configurable `max_restarts` parameter. The `is_running` property can be
+// queried to know if it's still running after having expired.
+//
+// When a timer is restarted, it will use a configurable `backoff_algorithm` to
+// possibly adjust the duration of the next expiry. It is also possible to
+// return a new base duration (which is the duration before it's adjusted by the
+// backoff algorithm).
+class Timer {
+ public:
+ // The maximum timer duration - one day.
+ static constexpr DurationMs kMaxTimerDuration = DurationMs(24 * 3600 * 1000);
+
+ // When expired, the timer handler can optionally return a new duration which
+ // will be set as `duration` and used as base duration when the timer is
+ // restarted and as input to the backoff algorithm.
+ using OnExpired = std::function<absl::optional<DurationMs>()>;
+
+ // TimerManager will have pointers to these instances, so they must not move.
+ Timer(const Timer&) = delete;
+ Timer& operator=(const Timer&) = delete;
+
+ ~Timer();
+
+ // Starts the timer if it's stopped or restarts the timer if it's already
+ // running. The `expiration_count` will be reset.
+ void Start();
+
+ // Stops the timer. This can also be called when the timer is already stopped.
+ // The `expiration_count` will be reset.
+ void Stop();
+
+ // Sets the base duration. The actual timer duration may be larger depending
+ // on the backoff algorithm.
+ void set_duration(DurationMs duration) {
+ duration_ = std::min(duration, kMaxTimerDuration);
+ }
+
+ // Retrieves the base duration. The actual timer duration may be larger
+ // depending on the backoff algorithm.
+ DurationMs duration() const { return duration_; }
+
+ // Returns the number of times the timer has expired.
+ int expiration_count() const { return expiration_count_; }
+
+ // Returns the timer's options.
+ const TimerOptions& options() const { return options_; }
+
+ // Returns the name of the timer.
+ absl::string_view name() const { return name_; }
+
+ // Indicates if this timer is currently running.
+ bool is_running() const { return is_running_; }
+
+ private:
+ friend class TimerManager;
+ using UnregisterHandler = std::function<void()>;
+ Timer(TimerID id,
+ absl::string_view name,
+ OnExpired on_expired,
+ UnregisterHandler unregister,
+ std::unique_ptr<Timeout> timeout,
+ const TimerOptions& options);
+
+ // Called by TimerManager. Will trigger the callback and increment
+ // `expiration_count`. The timer will automatically be restarted at the
+ // duration as decided by the backoff algorithm, unless the
+ // `TimerOptions::max_restarts` has been reached and then it will be stopped
+ // and `is_running()` will return false.
+ void Trigger(TimerGeneration generation);
+
+ const TimerID id_;
+ const std::string name_;
+ const TimerOptions options_;
+ const OnExpired on_expired_;
+ const UnregisterHandler unregister_handler_;
+ const std::unique_ptr<Timeout> timeout_;
+
+ DurationMs duration_;
+
+ // Increased on each start, and is matched on Trigger, to avoid races. And by
+ // race, meaning that a timeout - which may be evaluated/expired on a
+ // different thread while this thread has stopped that timer already. Note
+ // that the entire socket is not thread-safe, so `TimerManager::HandleTimeout`
+ // is never executed concurrently with any timer starting/stopping.
+ //
+ // This will wrap around after 4 billion timer restarts, and if it wraps
+ // around, it would just trigger _this_ timer in advance (but it's hard to
+ // restart it 4 billion times within its duration).
+ TimerGeneration generation_ = TimerGeneration(0);
+ bool is_running_ = false;
+ // Incremented each time time has expired and reset when stopped or restarted.
+ int expiration_count_ = 0;
+};
+
+// Creates and manages timers.
+class TimerManager {
+ public:
+ explicit TimerManager(
+ std::function<std::unique_ptr<Timeout>(
+ webrtc::TaskQueueBase::DelayPrecision)> create_timeout)
+ : create_timeout_(std::move(create_timeout)) {}
+
+ // Creates a timer with name `name` that will expire (when started) after
+ // `options.duration` and call `on_expired`. There are more `options` that
+ // affects the behavior. Note that timers are created initially stopped.
+ std::unique_ptr<Timer> CreateTimer(absl::string_view name,
+ Timer::OnExpired on_expired,
+ const TimerOptions& options);
+
+ void HandleTimeout(TimeoutID timeout_id);
+
+ private:
+ const std::function<std::unique_ptr<Timeout>(
+ webrtc::TaskQueueBase::DelayPrecision)>
+ create_timeout_;
+ std::map<TimerID, Timer*> timers_;
+ TimerID next_id_ = TimerID(0);
+};
+
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_TIMER_TIMER_H_