Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Timer.hpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2022 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#ifndef TOOLBOX_IO_TIMER_HPP
18#define TOOLBOX_IO_TIMER_HPP
19
20#include <limits>
21#include <toolbox/sys/Time.hpp>
22#include <toolbox/util/Slot.hpp>
23
24#include <toolbox/Config.h>
25
26#include <boost/intrusive_ptr.hpp>
27
28#include <memory>
29
30namespace toolbox {
31inline namespace io {
32
33class Timer;
34class TimerQueue;
36
38 friend class TimerQueue;
39
40 public:
53
54 explicit Timer(Impl* impl)
55 : impl_{impl, false}
56 {
57 }
58 Timer(std::nullptr_t = nullptr) noexcept {} // NOLINT(hicpp-explicit-conversions)
59 ~Timer() = default;
60
61 // Copy.
62 Timer(const Timer&) = default;
63 Timer& operator=(const Timer&) = default;
64
65 // Move.
66 Timer(Timer&&) noexcept = default;
67 Timer& operator=(Timer&&) noexcept = default;
68
69 bool empty() const noexcept { return !impl_; }
70 explicit operator bool() const noexcept { return impl_ != nullptr; }
71 long id() const noexcept { return impl_ ? impl_->id : 0; }
72 bool pending() const noexcept { return impl_ != nullptr && bool{impl_->slot}; }
73
74 MonoTime expiry() const noexcept { return impl_->expiry; }
75 Duration interval() const noexcept { return impl_->interval; }
77 template <typename RepT, typename PeriodT>
78 void set_interval(std::chrono::duration<RepT, PeriodT> interval) noexcept
79 {
80 using namespace std::chrono;
81 impl_->interval = duration_cast<Duration>(interval);
82 }
83 void reset(std::nullptr_t = nullptr) noexcept { impl_.reset(); }
84 void swap(Timer& rhs) noexcept { impl_.swap(rhs.impl_); }
85 void cancel() noexcept;
86
87 std::partial_ordering operator<=>(const Timer& rhs) const noexcept
88 {
89 if (!*this || !rhs) {
90 return std::partial_ordering::unordered;
91 }
92 return id() <=> rhs.id();
93 }
94
95 private:
96 void set_expiry(MonoTime expiry) noexcept { impl_->expiry = expiry; }
97 TimerSlot& slot() noexcept { return impl_->slot; }
98
99 boost::intrusive_ptr<Timer::Impl> impl_;
100};
101
103 using SlabPtr = std::unique_ptr<Timer::Impl[]>;
104
105 public:
106 TimerPool() = default;
107 ~TimerPool() noexcept = default;
108
109 // Copy.
110 TimerPool(const TimerPool&) = delete;
111 TimerPool& operator=(const TimerPool&) = delete;
112
113 // Move.
114 TimerPool(TimerPool&&) = delete;
115 TimerPool& operator=(TimerPool&&) = delete;
116
117 Timer::Impl* allocate();
118 void deallocate(Timer::Impl* impl) noexcept
119 {
120 assert(impl);
121 impl->next = free_;
122 free_ = impl;
123 }
124
125 private:
126 std::vector<SlabPtr> slabs_;
128 Timer::Impl* free_{nullptr};
129};
130
132 friend class Timer;
133 friend void intrusive_ptr_add_ref(Timer::Impl*) noexcept;
134 friend void intrusive_ptr_release(Timer::Impl*) noexcept;
135
136 using SlabPtr = std::unique_ptr<Timer::Impl[]>;
137
138 public:
141 TimerQueue(TimerPool& pool) // NOLINT(hicpp-explicit-conversions)
142 : pool_{pool}
143 {
144 }
145 ~TimerQueue() noexcept = default;
146
147 // Copy.
148 TimerQueue(const TimerQueue&) = delete;
149 TimerQueue& operator=(const TimerQueue&) = delete;
150
151 // Move.
153 TimerQueue& operator=(TimerQueue&&) = delete;
154
155 std::size_t size() const noexcept { return heap_.size() - cancelled_; }
156 bool empty() const noexcept { return size() == 0; }
157 const Timer& front() const { return heap_.front(); }
158
159 // clang-format off
161 [[nodiscard]] Timer insert(MonoTime expiry, Duration interval, TimerSlot slot);
163 [[nodiscard]] Timer insert(MonoTime expiry, TimerSlot slot)
164 {
165 return insert(expiry, Duration::zero(), slot);
166 }
167 // clang-format on
168
169 int dispatch(CyclTime now, int max_work = std::numeric_limits<int>::max());
170
171 private:
172 Timer allocate(MonoTime expiry, Duration interval, TimerSlot slot);
173 void cancel() noexcept;
174 void expire(CyclTime now);
175 void gc() noexcept;
176 Timer pop() noexcept;
177
178 TimerPool& pool_;
179 long max_id_{};
180 int cancelled_{};
182 std::vector<Timer> heap_;
183};
184
186{
187 ++impl->ref_count;
188}
189
191
193{
194 // If pending, then reset the slot and inform the queue that the timer has been cancelled.
195 if (impl_ && impl_->slot) {
196 impl_->slot.reset();
197 impl_->tq->cancel();
198 }
199}
200} // namespace io
201} // namespace toolbox
202
203#endif // TOOLBOX_IO_TIMER_HPP
#define TOOLBOX_API
Definition Config.h:39
~TimerPool() noexcept=default
Timer insert(MonoTime expiry, TimerSlot slot)
Throws std::bad_alloc only.
Definition Timer.hpp:163
TimerQueue(TimerPool &pool)
Definition Timer.hpp:141
const Timer & front() const
Definition Timer.hpp:157
bool empty() const noexcept
Definition Timer.hpp:156
~TimerQueue() noexcept=default
void set_interval(std::chrono::duration< RepT, PeriodT > interval) noexcept
Setting the interval will not reschedule any pending timer.
Definition Timer.hpp:78
Duration interval() const noexcept
Definition Timer.hpp:75
Timer & operator=(const Timer &)=default
long id() const noexcept
Definition Timer.hpp:71
Timer(std::nullptr_t=nullptr) noexcept
Definition Timer.hpp:58
Timer(const Timer &)=default
void cancel() noexcept
Definition Timer.hpp:192
void swap(Timer &rhs) noexcept
Definition Timer.hpp:84
bool pending() const noexcept
Definition Timer.hpp:72
void reset(std::nullptr_t=nullptr) noexcept
Definition Timer.hpp:83
MonoTime expiry() const noexcept
Definition Timer.hpp:74
Timer(Impl *impl)
Definition Timer.hpp:54
Timer(Timer &&) noexcept=default
STL namespace.
void intrusive_ptr_add_ref(Timer::Impl *impl) noexcept
Definition Timer.hpp:185
void dispatch(CyclTime now, const HookList &l) noexcept
Definition Hook.cpp:24
void intrusive_ptr_release(Timer::Impl *impl) noexcept
Definition Timer.cpp:181
MonoClock::time_point MonoTime
Definition Time.hpp:110
Nanos Duration
Definition Time.hpp:40
constexpr std::size_t size(const detail::Struct< detail::Member< TagsT, ValuesT >... > &s)
Definition Struct.hpp:98
constexpr auto bind() noexcept
Definition Slot.hpp:92
TOOLBOX_WEAK void * allocate(size_t size)
Definition Allocator.cpp:25
Impl * next
Singly-linked free-list.
Definition Timer.hpp:44