blob: 31b496dc816f3f38e97bd9f4c5e031a9f7e6194f [file] [log] [blame]
Victor Boivie6fa0cfa2021-03-30 22:54:41 +02001/*
2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10#ifndef NET_DCSCTP_TIMER_TIMER_H_
11#define NET_DCSCTP_TIMER_TIMER_H_
12
13#include <stdint.h>
14
Victor Boivie5d3bda52021-04-12 21:59:19 +020015#include <algorithm>
Victor Boivie6fa0cfa2021-03-30 22:54:41 +020016#include <functional>
Victor Boivie3ec9e032021-08-18 15:22:42 +020017#include <map>
Victor Boivie6fa0cfa2021-03-30 22:54:41 +020018#include <memory>
19#include <string>
Victor Boivie6fa0cfa2021-03-30 22:54:41 +020020#include <utility>
21
22#include "absl/strings/string_view.h"
23#include "absl/types/optional.h"
Henrik Boströmb951dc62022-01-26 18:38:13 +010024#include "api/task_queue/task_queue_base.h"
Victor Boivie6fa0cfa2021-03-30 22:54:41 +020025#include "net/dcsctp/public/timeout.h"
Victor Boivieb9182302021-09-21 14:51:05 +020026#include "rtc_base/strong_alias.h"
Victor Boivie6fa0cfa2021-03-30 22:54:41 +020027
28namespace dcsctp {
29
Victor Boivieb9182302021-09-21 14:51:05 +020030using TimerID = webrtc::StrongAlias<class TimerIDTag, uint32_t>;
31using TimerGeneration = webrtc::StrongAlias<class TimerGenerationTag, uint32_t>;
Victor Boivie5d3bda52021-04-12 21:59:19 +020032
Victor Boivie6fa0cfa2021-03-30 22:54:41 +020033enum class TimerBackoffAlgorithm {
34 // The base duration will be used for any restart.
35 kFixed,
36 // An exponential backoff is used for restarts, with a 2x multiplier, meaning
37 // that every restart will use a duration that is twice as long as the
38 // previous.
39 kExponential,
40};
41
42struct TimerOptions {
43 explicit TimerOptions(DurationMs duration)
44 : TimerOptions(duration, TimerBackoffAlgorithm::kExponential) {}
45 TimerOptions(DurationMs duration, TimerBackoffAlgorithm backoff_algorithm)
Victor Boivie9680d292021-08-30 10:23:49 +020046 : TimerOptions(duration, backoff_algorithm, absl::nullopt) {}
Victor Boivie6fa0cfa2021-03-30 22:54:41 +020047 TimerOptions(DurationMs duration,
48 TimerBackoffAlgorithm backoff_algorithm,
Victor Boivie9680d292021-08-30 10:23:49 +020049 absl::optional<int> max_restarts)
Victor Boiviecebbff72021-08-30 15:21:01 +020050 : TimerOptions(duration, backoff_algorithm, max_restarts, absl::nullopt) {
51 }
52 TimerOptions(DurationMs duration,
53 TimerBackoffAlgorithm backoff_algorithm,
54 absl::optional<int> max_restarts,
55 absl::optional<DurationMs> max_backoff_duration)
Henrik Boströmb951dc62022-01-26 18:38:13 +010056 : TimerOptions(duration,
57 backoff_algorithm,
58 max_restarts,
59 max_backoff_duration,
60 webrtc::TaskQueueBase::DelayPrecision::kLow) {}
61 TimerOptions(DurationMs duration,
62 TimerBackoffAlgorithm backoff_algorithm,
63 absl::optional<int> max_restarts,
64 absl::optional<DurationMs> max_backoff_duration,
65 webrtc::TaskQueueBase::DelayPrecision precision)
Victor Boivie6fa0cfa2021-03-30 22:54:41 +020066 : duration(duration),
67 backoff_algorithm(backoff_algorithm),
Victor Boiviecebbff72021-08-30 15:21:01 +020068 max_restarts(max_restarts),
Henrik Boströmb951dc62022-01-26 18:38:13 +010069 max_backoff_duration(max_backoff_duration),
70 precision(precision) {}
Victor Boivie6fa0cfa2021-03-30 22:54:41 +020071
72 // The initial timer duration. Can be overridden with `set_duration`.
73 const DurationMs duration;
74 // If the duration should be increased (using exponential backoff) when it is
75 // restarted. If not set, the same duration will be used.
76 const TimerBackoffAlgorithm backoff_algorithm;
Victor Boivie9680d292021-08-30 10:23:49 +020077 // The maximum number of times that the timer will be automatically restarted,
78 // or absl::nullopt if there is no limit.
79 const absl::optional<int> max_restarts;
Victor Boiviecebbff72021-08-30 15:21:01 +020080 // The maximum timeout value for exponential backoff.
81 const absl::optional<DurationMs> max_backoff_duration;
Henrik Boströmb951dc62022-01-26 18:38:13 +010082 // The precision of the webrtc::TaskQueueBase used for scheduling.
83 const webrtc::TaskQueueBase::DelayPrecision precision;
Victor Boivie6fa0cfa2021-03-30 22:54:41 +020084};
85
86// A high-level timer (in contrast to the low-level `Timeout` class).
87//
88// Timers are started and can be stopped or restarted. When a timer expires,
89// the provided `on_expired` callback will be triggered. A timer is
90// automatically restarted, as long as the number of restarts is below the
91// configurable `max_restarts` parameter. The `is_running` property can be
92// queried to know if it's still running after having expired.
93//
94// When a timer is restarted, it will use a configurable `backoff_algorithm` to
95// possibly adjust the duration of the next expiry. It is also possible to
96// return a new base duration (which is the duration before it's adjusted by the
97// backoff algorithm).
98class Timer {
99 public:
Victor Boivie5d3bda52021-04-12 21:59:19 +0200100 // The maximum timer duration - one day.
101 static constexpr DurationMs kMaxTimerDuration = DurationMs(24 * 3600 * 1000);
102
Victor Boivie6fa0cfa2021-03-30 22:54:41 +0200103 // When expired, the timer handler can optionally return a new duration which
104 // will be set as `duration` and used as base duration when the timer is
105 // restarted and as input to the backoff algorithm.
106 using OnExpired = std::function<absl::optional<DurationMs>()>;
107
108 // TimerManager will have pointers to these instances, so they must not move.
109 Timer(const Timer&) = delete;
110 Timer& operator=(const Timer&) = delete;
111
112 ~Timer();
113
114 // Starts the timer if it's stopped or restarts the timer if it's already
115 // running. The `expiration_count` will be reset.
116 void Start();
117
118 // Stops the timer. This can also be called when the timer is already stopped.
119 // The `expiration_count` will be reset.
120 void Stop();
121
122 // Sets the base duration. The actual timer duration may be larger depending
123 // on the backoff algorithm.
Victor Boivie5d3bda52021-04-12 21:59:19 +0200124 void set_duration(DurationMs duration) {
125 duration_ = std::min(duration, kMaxTimerDuration);
126 }
Victor Boivie6fa0cfa2021-03-30 22:54:41 +0200127
128 // Retrieves the base duration. The actual timer duration may be larger
129 // depending on the backoff algorithm.
130 DurationMs duration() const { return duration_; }
131
132 // Returns the number of times the timer has expired.
133 int expiration_count() const { return expiration_count_; }
134
135 // Returns the timer's options.
136 const TimerOptions& options() const { return options_; }
137
138 // Returns the name of the timer.
139 absl::string_view name() const { return name_; }
140
141 // Indicates if this timer is currently running.
142 bool is_running() const { return is_running_; }
143
144 private:
145 friend class TimerManager;
146 using UnregisterHandler = std::function<void()>;
Victor Boivie5d3bda52021-04-12 21:59:19 +0200147 Timer(TimerID id,
Victor Boivie6fa0cfa2021-03-30 22:54:41 +0200148 absl::string_view name,
149 OnExpired on_expired,
150 UnregisterHandler unregister,
151 std::unique_ptr<Timeout> timeout,
152 const TimerOptions& options);
153
154 // Called by TimerManager. Will trigger the callback and increment
155 // `expiration_count`. The timer will automatically be restarted at the
156 // duration as decided by the backoff algorithm, unless the
157 // `TimerOptions::max_restarts` has been reached and then it will be stopped
158 // and `is_running()` will return false.
Victor Boivie5d3bda52021-04-12 21:59:19 +0200159 void Trigger(TimerGeneration generation);
Victor Boivie6fa0cfa2021-03-30 22:54:41 +0200160
Victor Boivie5d3bda52021-04-12 21:59:19 +0200161 const TimerID id_;
Victor Boivie6fa0cfa2021-03-30 22:54:41 +0200162 const std::string name_;
163 const TimerOptions options_;
164 const OnExpired on_expired_;
165 const UnregisterHandler unregister_handler_;
166 const std::unique_ptr<Timeout> timeout_;
167
168 DurationMs duration_;
169
Victor Boivie5d3bda52021-04-12 21:59:19 +0200170 // Increased on each start, and is matched on Trigger, to avoid races. And by
171 // race, meaning that a timeout - which may be evaluated/expired on a
172 // different thread while this thread has stopped that timer already. Note
173 // that the entire socket is not thread-safe, so `TimerManager::HandleTimeout`
174 // is never executed concurrently with any timer starting/stopping.
175 //
176 // This will wrap around after 4 billion timer restarts, and if it wraps
177 // around, it would just trigger _this_ timer in advance (but it's hard to
178 // restart it 4 billion times within its duration).
179 TimerGeneration generation_ = TimerGeneration(0);
Victor Boivie6fa0cfa2021-03-30 22:54:41 +0200180 bool is_running_ = false;
181 // Incremented each time time has expired and reset when stopped or restarted.
182 int expiration_count_ = 0;
183};
184
185// Creates and manages timers.
186class TimerManager {
187 public:
188 explicit TimerManager(
Henrik Boströmb951dc62022-01-26 18:38:13 +0100189 std::function<std::unique_ptr<Timeout>(
190 webrtc::TaskQueueBase::DelayPrecision)> create_timeout)
Victor Boivie6fa0cfa2021-03-30 22:54:41 +0200191 : create_timeout_(std::move(create_timeout)) {}
192
193 // Creates a timer with name `name` that will expire (when started) after
194 // `options.duration` and call `on_expired`. There are more `options` that
195 // affects the behavior. Note that timers are created initially stopped.
196 std::unique_ptr<Timer> CreateTimer(absl::string_view name,
197 Timer::OnExpired on_expired,
198 const TimerOptions& options);
199
200 void HandleTimeout(TimeoutID timeout_id);
201
202 private:
Henrik Boströmb951dc62022-01-26 18:38:13 +0100203 const std::function<std::unique_ptr<Timeout>(
204 webrtc::TaskQueueBase::DelayPrecision)>
205 create_timeout_;
Victor Boivie3ec9e032021-08-18 15:22:42 +0200206 std::map<TimerID, Timer*> timers_;
Victor Boivie5d3bda52021-04-12 21:59:19 +0200207 TimerID next_id_ = TimerID(0);
Victor Boivie6fa0cfa2021-03-30 22:54:41 +0200208};
209
210} // namespace dcsctp
211
212#endif // NET_DCSCTP_TIMER_TIMER_H_