blob: 6b68c98374d10ecdd77bd650611744e95c7e62cc [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
15#include <functional>
16#include <memory>
17#include <string>
18#include <unordered_map>
19#include <utility>
20
21#include "absl/strings/string_view.h"
22#include "absl/types/optional.h"
23#include "net/dcsctp/public/timeout.h"
24
25namespace dcsctp {
26
27enum class TimerBackoffAlgorithm {
28 // The base duration will be used for any restart.
29 kFixed,
30 // An exponential backoff is used for restarts, with a 2x multiplier, meaning
31 // that every restart will use a duration that is twice as long as the
32 // previous.
33 kExponential,
34};
35
36struct TimerOptions {
37 explicit TimerOptions(DurationMs duration)
38 : TimerOptions(duration, TimerBackoffAlgorithm::kExponential) {}
39 TimerOptions(DurationMs duration, TimerBackoffAlgorithm backoff_algorithm)
40 : TimerOptions(duration, backoff_algorithm, -1) {}
41 TimerOptions(DurationMs duration,
42 TimerBackoffAlgorithm backoff_algorithm,
43 int max_restarts)
44 : duration(duration),
45 backoff_algorithm(backoff_algorithm),
46 max_restarts(max_restarts) {}
47
48 // The initial timer duration. Can be overridden with `set_duration`.
49 const DurationMs duration;
50 // If the duration should be increased (using exponential backoff) when it is
51 // restarted. If not set, the same duration will be used.
52 const TimerBackoffAlgorithm backoff_algorithm;
53 // The maximum number of times that the timer will be automatically restarted.
54 const int max_restarts;
55};
56
57// A high-level timer (in contrast to the low-level `Timeout` class).
58//
59// Timers are started and can be stopped or restarted. When a timer expires,
60// the provided `on_expired` callback will be triggered. A timer is
61// automatically restarted, as long as the number of restarts is below the
62// configurable `max_restarts` parameter. The `is_running` property can be
63// queried to know if it's still running after having expired.
64//
65// When a timer is restarted, it will use a configurable `backoff_algorithm` to
66// possibly adjust the duration of the next expiry. It is also possible to
67// return a new base duration (which is the duration before it's adjusted by the
68// backoff algorithm).
69class Timer {
70 public:
71 // When expired, the timer handler can optionally return a new duration which
72 // will be set as `duration` and used as base duration when the timer is
73 // restarted and as input to the backoff algorithm.
74 using OnExpired = std::function<absl::optional<DurationMs>()>;
75
76 // TimerManager will have pointers to these instances, so they must not move.
77 Timer(const Timer&) = delete;
78 Timer& operator=(const Timer&) = delete;
79
80 ~Timer();
81
82 // Starts the timer if it's stopped or restarts the timer if it's already
83 // running. The `expiration_count` will be reset.
84 void Start();
85
86 // Stops the timer. This can also be called when the timer is already stopped.
87 // The `expiration_count` will be reset.
88 void Stop();
89
90 // Sets the base duration. The actual timer duration may be larger depending
91 // on the backoff algorithm.
92 void set_duration(DurationMs duration) { duration_ = duration; }
93
94 // Retrieves the base duration. The actual timer duration may be larger
95 // depending on the backoff algorithm.
96 DurationMs duration() const { return duration_; }
97
98 // Returns the number of times the timer has expired.
99 int expiration_count() const { return expiration_count_; }
100
101 // Returns the timer's options.
102 const TimerOptions& options() const { return options_; }
103
104 // Returns the name of the timer.
105 absl::string_view name() const { return name_; }
106
107 // Indicates if this timer is currently running.
108 bool is_running() const { return is_running_; }
109
110 private:
111 friend class TimerManager;
112 using UnregisterHandler = std::function<void()>;
113 Timer(uint32_t id,
114 absl::string_view name,
115 OnExpired on_expired,
116 UnregisterHandler unregister,
117 std::unique_ptr<Timeout> timeout,
118 const TimerOptions& options);
119
120 // Called by TimerManager. Will trigger the callback and increment
121 // `expiration_count`. The timer will automatically be restarted at the
122 // duration as decided by the backoff algorithm, unless the
123 // `TimerOptions::max_restarts` has been reached and then it will be stopped
124 // and `is_running()` will return false.
125 void Trigger(uint32_t generation);
126
127 const uint32_t id_;
128 const std::string name_;
129 const TimerOptions options_;
130 const OnExpired on_expired_;
131 const UnregisterHandler unregister_handler_;
132 const std::unique_ptr<Timeout> timeout_;
133
134 DurationMs duration_;
135
136 // Increased on each start, and is matched on Trigger, to avoid races.
137 uint32_t generation_ = 0;
138 bool is_running_ = false;
139 // Incremented each time time has expired and reset when stopped or restarted.
140 int expiration_count_ = 0;
141};
142
143// Creates and manages timers.
144class TimerManager {
145 public:
146 explicit TimerManager(
147 std::function<std::unique_ptr<Timeout>()> create_timeout)
148 : create_timeout_(std::move(create_timeout)) {}
149
150 // Creates a timer with name `name` that will expire (when started) after
151 // `options.duration` and call `on_expired`. There are more `options` that
152 // affects the behavior. Note that timers are created initially stopped.
153 std::unique_ptr<Timer> CreateTimer(absl::string_view name,
154 Timer::OnExpired on_expired,
155 const TimerOptions& options);
156
157 void HandleTimeout(TimeoutID timeout_id);
158
159 private:
160 const std::function<std::unique_ptr<Timeout>()> create_timeout_;
161 std::unordered_map<int, Timer*> timers_;
162 uint32_t next_id_ = 0;
163};
164
165} // namespace dcsctp
166
167#endif // NET_DCSCTP_TIMER_TIMER_H_