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 <toolbox/sys/Time.hpp>
21#include <toolbox/util/Slot.hpp>
22
23#include <toolbox/Config.h>
24
25#include <boost/intrusive_ptr.hpp>
26
27#include <memory>
28
29namespace toolbox {
30inline namespace io {
31
32class Timer;
33class TimerQueue;
35
37 friend class TimerQueue;
38
39 public:
52
53 explicit Timer(Impl* impl)
54 : impl_{impl, false}
55 {
56 }
57 Timer(std::nullptr_t = nullptr) noexcept {} // NOLINT(hicpp-explicit-conversions)
58 ~Timer() = default;
59
60 // Copy.
61 Timer(const Timer&) = default;
62 Timer& operator=(const Timer&) = default;
63
64 // Move.
65 Timer(Timer&&) noexcept = default;
66 Timer& operator=(Timer&&) noexcept = default;
67
68 bool empty() const noexcept { return !impl_; }
69 explicit operator bool() const noexcept { return impl_ != nullptr; }
70 long id() const noexcept { return impl_ ? impl_->id : 0; }
71 bool pending() const noexcept { return impl_ != nullptr && bool{impl_->slot}; }
72
73 MonoTime expiry() const noexcept { return impl_->expiry; }
74 Duration interval() const noexcept { return impl_->interval; }
76 template <typename RepT, typename PeriodT>
77 void set_interval(std::chrono::duration<RepT, PeriodT> interval) noexcept
78 {
79 using namespace std::chrono;
80 impl_->interval = duration_cast<Duration>(interval);
81 }
82 void reset(std::nullptr_t = nullptr) noexcept { impl_.reset(); }
83 void swap(Timer& rhs) noexcept { impl_.swap(rhs.impl_); }
84 void cancel() noexcept;
85
86 std::partial_ordering operator<=>(const Timer& rhs) const noexcept
87 {
88 if (!*this || !rhs) {
89 return std::partial_ordering::unordered;
90 }
91 return id() <=> rhs.id();
92 }
93
94 private:
95 void set_expiry(MonoTime expiry) noexcept { impl_->expiry = expiry; }
96 TimerSlot& slot() noexcept { return impl_->slot; }
97
98 boost::intrusive_ptr<Timer::Impl> impl_;
99};
100
102 using SlabPtr = std::unique_ptr<Timer::Impl[]>;
103
104 public:
105 TimerPool() = default;
106 ~TimerPool() noexcept = default;
107
108 // Copy.
109 TimerPool(const TimerPool&) = delete;
110 TimerPool& operator=(const TimerPool&) = delete;
111
112 // Move.
113 TimerPool(TimerPool&&) = delete;
114 TimerPool& operator=(TimerPool&&) = delete;
115
116 Timer::Impl* allocate(MonoTime expiry, Duration interval, TimerSlot slot);
117 void deallocate(Timer::Impl* impl) noexcept
118 {
119 assert(impl);
120 impl->next = free_;
121 free_ = impl;
122 }
123
124 private:
125 std::vector<SlabPtr> slabs_;
127 Timer::Impl* free_{nullptr};
129 std::vector<Timer> heap_;
130};
131
133 friend class Timer;
134 friend void intrusive_ptr_add_ref(Timer::Impl*) noexcept;
135 friend void intrusive_ptr_release(Timer::Impl*) noexcept;
136
137 using SlabPtr = std::unique_ptr<Timer::Impl[]>;
138
139 public:
142 TimerQueue(TimerPool& pool) // NOLINT(hicpp-explicit-conversions)
143 : pool_{pool}
144 {
145 }
146 ~TimerQueue() noexcept = default;
147
148 // Copy.
149 TimerQueue(const TimerQueue&) = delete;
150 TimerQueue& operator=(const TimerQueue&) = delete;
151
152 // Move.
154 TimerQueue& operator=(TimerQueue&&) = delete;
155
156 std::size_t size() const noexcept { return heap_.size() - cancelled_; }
157 bool empty() const noexcept { return size() == 0; }
158 const Timer& front() const { return heap_.front(); }
159
160 // clang-format off
162 [[nodiscard]] Timer insert(MonoTime expiry, Duration interval, TimerSlot slot);
164 [[nodiscard]] Timer insert(MonoTime expiry, TimerSlot slot)
165 {
166 return insert(expiry, Duration::zero(), slot);
167 }
168 // clang-format on
169
170 int dispatch(CyclTime now);
171
172 private:
173 Timer allocate(MonoTime expiry, Duration interval, TimerSlot slot);
174 void cancel() noexcept;
175 void expire(CyclTime now);
176 void gc() noexcept;
177 Timer pop() noexcept;
178
179 TimerPool& pool_;
180 long max_id_{};
181 int cancelled_{};
183 std::vector<Timer> heap_;
184};
185
187{
188 ++impl->ref_count;
189}
190
192
194{
195 // If pending, then reset the slot and inform the queue that the timer has been cancelled.
196 if (impl_ && impl_->slot) {
197 impl_->slot.reset();
198 impl_->tq->cancel();
199 }
200}
201} // namespace io
202} // namespace toolbox
203
204#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:164
TimerQueue(TimerPool &pool)
Definition Timer.hpp:142
const Timer & front() const
Definition Timer.hpp:158
bool empty() const noexcept
Definition Timer.hpp:157
~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:77
Duration interval() const noexcept
Definition Timer.hpp:74
Timer & operator=(const Timer &)=default
long id() const noexcept
Definition Timer.hpp:70
Timer(std::nullptr_t=nullptr) noexcept
Definition Timer.hpp:57
Timer(const Timer &)=default
void cancel() noexcept
Definition Timer.hpp:193
void swap(Timer &rhs) noexcept
Definition Timer.hpp:83
bool pending() const noexcept
Definition Timer.hpp:71
void reset(std::nullptr_t=nullptr) noexcept
Definition Timer.hpp:82
MonoTime expiry() const noexcept
Definition Timer.hpp:73
Timer(Impl *impl)
Definition Timer.hpp:53
Timer(Timer &&) noexcept=default
STL namespace.
void intrusive_ptr_add_ref(Timer::Impl *impl) noexcept
Definition Timer.hpp:186
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:43