rippled
Loading...
Searching...
No Matches
src/test/csf/Scheduler.h
1#pragma once
2
3#include <xrpl/basics/ByteUtilities.h>
4#include <xrpl/beast/clock/manual_clock.h>
5
6#include <boost/container/pmr/monotonic_buffer_resource.hpp>
7#include <boost/intrusive/set.hpp>
8
9#include <type_traits>
10#include <utility>
11
12namespace xrpl {
13namespace test {
14namespace csf {
15
28{
29public:
31
33
35
36private:
37 using by_when_hook = boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>;
38
40 {
42
43 event(event const&) = delete;
44 event&
45 operator=(event const&) = delete;
46
47 virtual ~event() = default;
48
49 // Called to perform the event
50 virtual void
51 operator()() const = 0;
52
53 event(time_point when_) : when(when_)
54 {
55 }
56
57 bool
58 operator<(event const& other) const
59 {
60 return when < other.when;
61 }
62 };
63
64 template <class Handler>
65 class event_impl : public event
66 {
67 Handler const h_;
68
69 public:
70 event_impl(event_impl const&) = delete;
71
73 operator=(event_impl const&) = delete;
74
75 template <class DeducedHandler>
76 event_impl(time_point when_, DeducedHandler&& h) : event(when_), h_(std::forward<DeducedHandler>(h))
77 {
78 }
79
80 void
81 operator()() const override
82 {
83 h_();
84 }
85 };
86
88 {
89 private:
91 typename boost::intrusive::make_multiset<event, boost::intrusive::constant_time_size<false>>::type;
92 // alloc_ is owned by the scheduler
93 boost::container::pmr::monotonic_buffer_resource* alloc_;
95
96 public:
97 using iterator = typename by_when_set::iterator;
98
99 queue_type(queue_type const&) = delete;
101 operator=(queue_type const&) = delete;
102
103 explicit queue_type(boost::container::pmr::monotonic_buffer_resource* alloc);
104
105 ~queue_type();
106
107 bool
108 empty() const;
109
111 begin();
112
114 end();
115
116 template <class Handler>
117 typename by_when_set::iterator
118 emplace(time_point when, Handler&& h);
119
121 erase(iterator iter);
122 };
123
124 boost::container::pmr::monotonic_buffer_resource alloc_{kilobytes(256)};
126
127 // Aged containers that rely on this clock take a non-const reference =(
129
130public:
131 Scheduler(Scheduler const&) = delete;
132 Scheduler&
133 operator=(Scheduler const&) = delete;
134
135 Scheduler();
136
139 clock() const;
140
146 now() const;
147
148 // Used to cancel timers
149 struct cancel_token;
150
159 template <class Function>
161 at(time_point const& when, Function&& f);
162
171 template <class Function>
173 in(duration const& delay, Function&& f);
174
182 void
183 cancel(cancel_token const& token);
184
194 bool
195 step_one();
196
206 bool
207 step();
208
222 template <class Function>
223 bool
224 step_while(Function&& func);
225
235 bool
236 step_until(time_point const& until);
237
247 template <class Period, class Rep>
248 bool
250};
251
252//------------------------------------------------------------------------------
253
254inline Scheduler::queue_type::queue_type(boost::container::pmr::monotonic_buffer_resource* alloc) : alloc_(alloc)
255{
256}
257
259{
260 for (auto iter = by_when_.begin(); iter != by_when_.end();)
261 {
262 auto e = &*iter;
263 ++iter;
264 e->~event();
265 alloc_->deallocate(e, sizeof(e));
266 }
267}
268
269inline bool
271{
272 return by_when_.empty();
273}
274
275inline auto
277{
278 return by_when_.begin();
279}
280
281inline auto
283{
284 return by_when_.end();
285}
286
287template <class Handler>
288inline auto
289Scheduler::queue_type::emplace(time_point when, Handler&& h) -> typename by_when_set::iterator
290{
291 using event_type = event_impl<std::decay_t<Handler>>;
292 auto const p = alloc_->allocate(sizeof(event_type));
293 auto& e = *new (p) event_type(when, std::forward<Handler>(h));
294 return by_when_.insert(e);
295}
296
297inline auto
298Scheduler::queue_type::erase(iterator iter) -> typename by_when_set::iterator
299{
300 auto& e = *iter;
301 auto next = by_when_.erase(iter);
302 e.~event();
303 alloc_->deallocate(&e, sizeof(e));
304 return next;
305}
306
307//-----------------------------------------------------------------------------
309{
310private:
312
313public:
314 cancel_token() = delete;
315 cancel_token(cancel_token const&) = default;
317 operator=(cancel_token const&) = default;
318
319private:
320 friend class Scheduler;
321 cancel_token(typename queue_type::iterator iter) : iter_(iter)
322 {
323 }
324};
325
326//------------------------------------------------------------------------------
328{
329}
330
331inline auto
333{
334 return clock_;
335}
336
337inline auto
339{
340 return clock_.now();
341}
342
343template <class Function>
344inline auto
345Scheduler::at(time_point const& when, Function&& f) -> cancel_token
346{
347 return queue_.emplace(when, std::forward<Function>(f));
348}
349
350template <class Function>
351inline auto
352Scheduler::in(duration const& delay, Function&& f) -> cancel_token
353{
354 return at(clock_.now() + delay, std::forward<Function>(f));
355}
356
357inline void
359{
360 queue_.erase(token.iter_);
361}
362
363inline bool
365{
366 if (queue_.empty())
367 return false;
368 auto const iter = queue_.begin();
369 clock_.set(iter->when);
370 (*iter)();
371 queue_.erase(iter);
372 return true;
373}
374
375inline bool
377{
378 if (!step_one())
379 return false;
380 for (;;)
381 if (!step_one())
382 break;
383 return true;
384}
385
386template <class Function>
387inline bool
389{
390 bool ran = false;
391 while (f() && step_one())
392 ran = true;
393 return ran;
394}
395
396inline bool
398{
399 // VFALCO This routine needs optimizing
400 if (queue_.empty())
401 {
402 clock_.set(until);
403 return false;
404 }
405 auto iter = queue_.begin();
406 if (iter->when > until)
407 {
408 clock_.set(until);
409 return true;
410 }
411 do
412 {
413 step_one();
414 iter = queue_.begin();
415 } while (iter != queue_.end() && iter->when <= until);
416 clock_.set(until);
417 return iter != queue_.end();
418}
419
420template <class Period, class Rep>
421inline bool
426
427} // namespace csf
428} // namespace test
429} // namespace xrpl
typename Clock::time_point time_point
typename Clock::duration duration
time_point now() const override
Returns the current time.
void set(time_point const &when)
Set the current time of the manual clock.
event_impl & operator=(event_impl const &)=delete
event_impl(time_point when_, DeducedHandler &&h)
event_impl(event_impl const &)=delete
queue_type & operator=(queue_type const &)=delete
queue_type(queue_type const &)=delete
typename by_when_set::iterator iterator
boost::container::pmr::monotonic_buffer_resource * alloc_
typename boost::intrusive::make_multiset< event, boost::intrusive::constant_time_size< false > >::type by_when_set
by_when_set::iterator emplace(time_point when, Handler &&h)
Simulated discrete-event scheduler.
cancel_token in(duration const &delay, Function &&f)
Schedule an event after a specified duration passes.
clock_type & clock() const
Return the clock.
bool step()
Run the scheduler until no events remain.
time_point now() const
Return the current network time.
bool step_for(std::chrono::duration< Period, Rep > const &amount)
Run the scheduler until time has elapsed.
typename clock_type::duration duration
bool step_while(Function &&func)
Run the scheduler while a condition is true.
boost::intrusive::set_base_hook< boost::intrusive::link_mode< boost::intrusive::normal_link > > by_when_hook
typename clock_type::time_point time_point
bool step_one()
Run the scheduler for up to one event.
Scheduler & operator=(Scheduler const &)=delete
boost::container::pmr::monotonic_buffer_resource alloc_
void cancel(cancel_token const &token)
Cancel a timer.
cancel_token at(time_point const &when, Function &&f)
Schedule an event at a specific time.
Scheduler(Scheduler const &)=delete
bool step_until(time_point const &until)
Run the scheduler until the specified time.
T is_same_v
STL namespace.
auto const amount
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
constexpr auto kilobytes(T value) noexcept
cancel_token(typename queue_type::iterator iter)
cancel_token & operator=(cancel_token const &)=default
cancel_token(cancel_token const &)=default
event & operator=(event const &)=delete
virtual void operator()() const =0
bool operator<(event const &other) const
event(event const &)=delete