16#include <seastar/core/bitset-iter.hh>
18#include <seastar/util/assert.hh>
20#include <boost/intrusive/list.hpp>
30void log_timer_callback_exception(std::exception_ptr)
noexcept;
44template<
typename Timer, boost::
intrusive::list_member_hook<> Timer::*link>
47 using time_point =
typename Timer::time_point;
48 using timer_list_t = boost::intrusive::list<Timer, boost::intrusive::member_hook<Timer, boost::intrusive::list_member_hook<>, link>>;
50 using duration =
typename Timer::duration;
51 using timestamp_t =
typename Timer::duration::rep;
53 static constexpr timestamp_t max_timestamp = std::numeric_limits<timestamp_t>::max();
54 static constexpr int timestamp_bits = std::numeric_limits<timestamp_t>::digits;
57 static constexpr int n_buckets = timestamp_bits + 1;
59 std::array<timer_list_t, n_buckets> _buckets;
63 std::bitset<n_buckets> _non_empty_buckets;
65 static timestamp_t get_timestamp(time_point _time_point)
noexcept
67 return _time_point.time_since_epoch().count();
70 static timestamp_t get_timestamp(Timer&
timer)
noexcept
75 int get_index(timestamp_t timestamp)
const noexcept
77 if (timestamp <= _last) {
81 auto index = bitsets::count_leading_zeros(timestamp ^ _last);
82 SEASTAR_ASSERT(index < n_buckets - 1);
86 int get_index(Timer&
timer)
const noexcept
88 return get_index(get_timestamp(
timer));
91 int get_last_non_empty_bucket()
const noexcept
93 return bitsets::get_last_set(_non_empty_buckets);
99 , _next(max_timestamp)
100 , _non_empty_buckets(0)
105 for (
auto&& list : _buckets) {
106 while (!list.empty()) {
107 auto&
timer = *list.begin();
132 auto timestamp = get_timestamp(
timer);
133 auto index = get_index(timestamp);
135 _buckets[index].push_back(
timer);
136 _non_empty_buckets[index] =
true;
138 if (timestamp < _next) {
158 auto index = get_index(
timer);
159 auto& list = _buckets[index];
160 list.erase(list.iterator_to(
timer));
162 _non_empty_buckets[index] =
false;
171 if (
timer._expired) {
172 expired.erase(expired.iterator_to(
timer));
173 timer._expired =
false;
193 timer_list_t
expire(time_point now)
noexcept
196 auto timestamp = get_timestamp(now);
198 if (timestamp < _last) {
202 auto index = get_index(timestamp);
204 for (
int i : bitsets::for_each_set(_non_empty_buckets, index + 1)) {
205 exp.splice(exp.end(), _buckets[i]);
206 _non_empty_buckets[i] =
false;
210 _next = max_timestamp;
212 auto& list = _buckets[index];
213 while (!list.empty()) {
214 auto&
timer = *list.begin();
217 exp.push_back(
timer);
223 _non_empty_buckets[index] = !list.empty();
225 if (_next == max_timestamp && _non_empty_buckets.any()) {
226 for (
auto&
timer : _buckets[get_last_non_empty_bucket()]) {
227 _next = std::min(_next, get_timestamp(
timer));
233 template <
typename EnableFunc>
234 void complete(timer_list_t& expired_timers, EnableFunc&& enable_fn)
noexcept(
noexcept(enable_fn())) {
235 expired_timers =
expire(this->now());
236 for (
auto& t : expired_timers) {
240 while (!expired_timers.empty()) {
241 auto t = &*expired_timers.begin();
242 expired_timers.pop_front();
250 *internal::current_scheduling_group_ptr() = t->_sg;
253 internal::log_timer_callback_exception(std::current_exception());
259 *internal::current_scheduling_group_ptr() = prev_sg;
271 return time_point(duration(std::max(_last, _next)));
279 for (
int i : bitsets::for_each_set(_non_empty_buckets)) {
284 size_t size() const noexcept
287 for (
int i : bitsets::for_each_set(_non_empty_buckets)) {
288 res += _buckets[i].size();
298 return _non_empty_buckets.none();
301 time_point now() noexcept {
Definition: timer-set.hh:45
bool insert(Timer &timer) noexcept
Definition: timer-set.hh:130
void clear() noexcept
Definition: timer-set.hh:277
time_point get_next_timeout() const noexcept
Definition: timer-set.hh:269
void remove(Timer &timer, timer_list_t &expired) noexcept
Definition: timer-set.hh:169
timer_list_t expire(time_point now) noexcept
Definition: timer-set.hh:193
void remove(Timer &timer) noexcept
Definition: timer-set.hh:156
bool empty() const noexcept
Definition: timer-set.hh:296
time_point get_timeout() const noexcept
Definition: timer.hh:218
future now()
Returns a ready future.
Definition: later.hh:35
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
scheduling_group current_scheduling_group() noexcept
Returns the current scheduling group.
Definition: scheduling.hh:405