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:
38 boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>;
39
41 {
43
44 event(event const&) = delete;
45 event&
46 operator=(event const&) = delete;
47
48 virtual ~event() = default;
49
50 // Called to perform the event
51 virtual void
52 operator()() const = 0;
53
54 event(time_point when_) : when(when_)
55 {
56 }
57
58 bool
59 operator<(event const& other) const
60 {
61 return when < other.when;
62 }
63 };
64
65 template <class Handler>
66 class event_impl : public event
67 {
68 Handler const h_;
69
70 public:
71 event_impl(event_impl const&) = delete;
72
74 operator=(event_impl const&) = delete;
75
76 template <class DeducedHandler>
77 event_impl(time_point when_, DeducedHandler&& h)
78 : event(when_), h_(std::forward<DeducedHandler>(h))
79 {
80 }
81
82 void
83 operator()() const override
84 {
85 h_();
86 }
87 };
88
90 {
91 private:
92 using by_when_set = typename boost::intrusive::
93 make_multiset<event, boost::intrusive::constant_time_size<false>>::type;
94 // alloc_ is owned by the scheduler
95 boost::container::pmr::monotonic_buffer_resource* alloc_;
97
98 public:
99 using iterator = typename by_when_set::iterator;
100
101 queue_type(queue_type const&) = delete;
103 operator=(queue_type const&) = delete;
104
105 explicit queue_type(boost::container::pmr::monotonic_buffer_resource* alloc);
106
107 ~queue_type();
108
109 bool
110 empty() const;
111
113 begin();
114
116 end();
117
118 template <class Handler>
119 typename by_when_set::iterator
120 emplace(time_point when, Handler&& h);
121
123 erase(iterator iter);
124 };
125
126 boost::container::pmr::monotonic_buffer_resource alloc_{kilobytes(256)};
128
129 // Aged containers that rely on this clock take a non-const reference =(
131
132public:
133 Scheduler(Scheduler const&) = delete;
134 Scheduler&
135 operator=(Scheduler const&) = delete;
136
137 Scheduler();
138
141 clock() const;
142
148 now() const;
149
150 // Used to cancel timers
151 struct cancel_token;
152
161 template <class Function>
163 at(time_point const& when, Function&& f);
164
173 template <class Function>
175 in(duration const& delay, Function&& f);
176
184 void
185 cancel(cancel_token const& token);
186
196 bool
197 step_one();
198
208 bool
209 step();
210
224 template <class Function>
225 bool
226 step_while(Function&& func);
227
237 bool
238 step_until(time_point const& until);
239
249 template <class Period, class Rep>
250 bool
252};
253
254//------------------------------------------------------------------------------
255
256inline Scheduler::queue_type::queue_type(boost::container::pmr::monotonic_buffer_resource* alloc)
257 : alloc_(alloc)
258{
259}
260
262{
263 for (auto iter = by_when_.begin(); iter != by_when_.end();)
264 {
265 auto e = &*iter;
266 ++iter;
267 e->~event();
268 alloc_->deallocate(e, sizeof(e));
269 }
270}
271
272inline bool
274{
275 return by_when_.empty();
276}
277
278inline auto
280{
281 return by_when_.begin();
282}
283
284inline auto
286{
287 return by_when_.end();
288}
289
290template <class Handler>
291inline auto
292Scheduler::queue_type::emplace(time_point when, Handler&& h) -> typename by_when_set::iterator
293{
294 using event_type = event_impl<std::decay_t<Handler>>;
295 auto const p = alloc_->allocate(sizeof(event_type));
296 auto& e = *new (p) event_type(when, std::forward<Handler>(h));
297 return by_when_.insert(e);
298}
299
300inline auto
301Scheduler::queue_type::erase(iterator iter) -> typename by_when_set::iterator
302{
303 auto& e = *iter;
304 auto next = by_when_.erase(iter);
305 e.~event();
306 alloc_->deallocate(&e, sizeof(e));
307 return next;
308}
309
310//-----------------------------------------------------------------------------
312{
313private:
315
316public:
317 cancel_token() = delete;
318 cancel_token(cancel_token const&) = default;
320 operator=(cancel_token const&) = default;
321
322private:
323 friend class Scheduler;
324 cancel_token(typename queue_type::iterator iter) : iter_(iter)
325 {
326 }
327};
328
329//------------------------------------------------------------------------------
331{
332}
333
334inline auto
336{
337 return clock_;
338}
339
340inline auto
342{
343 return clock_.now();
344}
345
346template <class Function>
347inline auto
348Scheduler::at(time_point const& when, Function&& f) -> cancel_token
349{
350 return queue_.emplace(when, std::forward<Function>(f));
351}
352
353template <class Function>
354inline auto
355Scheduler::in(duration const& delay, Function&& f) -> cancel_token
356{
357 return at(clock_.now() + delay, std::forward<Function>(f));
358}
359
360inline void
362{
363 queue_.erase(token.iter_);
364}
365
366inline bool
368{
369 if (queue_.empty())
370 return false;
371 auto const iter = queue_.begin();
372 clock_.set(iter->when);
373 (*iter)();
374 queue_.erase(iter);
375 return true;
376}
377
378inline bool
380{
381 if (!step_one())
382 return false;
383 for (;;)
384 if (!step_one())
385 break;
386 return true;
387}
388
389template <class Function>
390inline bool
392{
393 bool ran = false;
394 while (f() && step_one())
395 ran = true;
396 return ran;
397}
398
399inline bool
401{
402 // VFALCO This routine needs optimizing
403 if (queue_.empty())
404 {
405 clock_.set(until);
406 return false;
407 }
408 auto iter = queue_.begin();
409 if (iter->when > until)
410 {
411 clock_.set(until);
412 return true;
413 }
414 do
415 {
416 step_one();
417 iter = queue_.begin();
418 } while (iter != queue_.end() && iter->when <= until);
419 clock_.set(until);
420 return iter != queue_.end();
421}
422
423template <class Period, class Rep>
424inline bool
429
430} // namespace csf
431} // namespace test
432} // 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
typename boost::intrusive::make_multiset< event, boost::intrusive::constant_time_size< false > >::type by_when_set
queue_type(queue_type const &)=delete
typename by_when_set::iterator iterator
boost::container::pmr::monotonic_buffer_resource * alloc_
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.
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