rippled
Loading...
Searching...
No Matches
src/test/csf/Scheduler.h
1#ifndef XRPL_TEST_CSF_SCHEDULER_H_INCLUDED
2#define XRPL_TEST_CSF_SCHEDULER_H_INCLUDED
3
4#include <xrpl/basics/ByteUtilities.h>
5#include <xrpl/beast/clock/manual_clock.h>
6
7#include <boost/container/pmr/monotonic_buffer_resource.hpp>
8#include <boost/intrusive/set.hpp>
9
10#include <type_traits>
11#include <utility>
12
13namespace ripple {
14namespace test {
15namespace csf {
16
29{
30public:
32
34
36
37private:
38 using by_when_hook = boost::intrusive::set_base_hook<
39 boost::intrusive::link_mode<boost::intrusive::normal_link>>;
40
42 {
44
45 event(event const&) = delete;
46 event&
47 operator=(event const&) = delete;
48
49 virtual ~event() = default;
50
51 // Called to perform the event
52 virtual void
53 operator()() const = 0;
54
55 event(time_point when_) : when(when_)
56 {
57 }
58
59 bool
60 operator<(event const& other) const
61 {
62 return when < other.when;
63 }
64 };
65
66 template <class Handler>
67 class event_impl : public event
68 {
69 Handler const h_;
70
71 public:
72 event_impl(event_impl const&) = delete;
73
75 operator=(event_impl const&) = delete;
76
77 template <class DeducedHandler>
78 event_impl(time_point when_, DeducedHandler&& h)
79 : event(when_), h_(std::forward<DeducedHandler>(h))
80 {
81 }
82
83 void
84 operator()() const override
85 {
86 h_();
87 }
88 };
89
91 {
92 private:
93 using by_when_set = typename boost::intrusive::make_multiset<
94 event,
95 boost::intrusive::constant_time_size<false>>::type;
96 // alloc_ is owned by the scheduler
97 boost::container::pmr::monotonic_buffer_resource* alloc_;
99
100 public:
101 using iterator = typename by_when_set::iterator;
102
103 queue_type(queue_type const&) = delete;
105 operator=(queue_type const&) = delete;
106
107 explicit queue_type(
108 boost::container::pmr::monotonic_buffer_resource* alloc);
109
110 ~queue_type();
111
112 bool
113 empty() const;
114
116 begin();
117
119 end();
120
121 template <class Handler>
122 typename by_when_set::iterator
123 emplace(time_point when, Handler&& h);
124
126 erase(iterator iter);
127 };
128
129 boost::container::pmr::monotonic_buffer_resource alloc_{kilobytes(256)};
131
132 // Aged containers that rely on this clock take a non-const reference =(
134
135public:
136 Scheduler(Scheduler const&) = delete;
137 Scheduler&
138 operator=(Scheduler const&) = delete;
139
140 Scheduler();
141
144 clock() const;
145
151 now() const;
152
153 // Used to cancel timers
154 struct cancel_token;
155
164 template <class Function>
166 at(time_point const& when, Function&& f);
167
176 template <class Function>
178 in(duration const& delay, Function&& f);
179
187 void
188 cancel(cancel_token const& token);
189
199 bool
200 step_one();
201
211 bool
212 step();
213
227 template <class Function>
228 bool
229 step_while(Function&& func);
230
240 bool
241 step_until(time_point const& until);
242
252 template <class Period, class Rep>
253 bool
255};
256
257//------------------------------------------------------------------------------
258
260 boost::container::pmr::monotonic_buffer_resource* alloc)
261 : alloc_(alloc)
262{
263}
264
266{
267 for (auto iter = by_when_.begin(); iter != by_when_.end();)
268 {
269 auto e = &*iter;
270 ++iter;
271 e->~event();
272 alloc_->deallocate(e, sizeof(e));
273 }
274}
275
276inline bool
278{
279 return by_when_.empty();
280}
281
282inline auto
284{
285 return by_when_.begin();
286}
287
288inline auto
290{
291 return by_when_.end();
292}
293
294template <class Handler>
295inline auto
297 typename by_when_set::iterator
298{
299 using event_type = event_impl<std::decay_t<Handler>>;
300 auto const p = alloc_->allocate(sizeof(event_type));
301 auto& e = *new (p) event_type(when, std::forward<Handler>(h));
302 return by_when_.insert(e);
303}
304
305inline auto
306Scheduler::queue_type::erase(iterator iter) -> typename by_when_set::iterator
307{
308 auto& e = *iter;
309 auto next = by_when_.erase(iter);
310 e.~event();
311 alloc_->deallocate(&e, sizeof(e));
312 return next;
313}
314
315//-----------------------------------------------------------------------------
317{
318private:
320
321public:
322 cancel_token() = delete;
323 cancel_token(cancel_token const&) = default;
325 operator=(cancel_token const&) = default;
326
327private:
328 friend class Scheduler;
329 cancel_token(typename queue_type::iterator iter) : iter_(iter)
330 {
331 }
332};
333
334//------------------------------------------------------------------------------
336{
337}
338
339inline auto
341{
342 return clock_;
343}
344
345inline auto
347{
348 return clock_.now();
349}
350
351template <class Function>
352inline auto
353Scheduler::at(time_point const& when, Function&& f) -> cancel_token
354{
355 return queue_.emplace(when, std::forward<Function>(f));
356}
357
358template <class Function>
359inline auto
360Scheduler::in(duration const& delay, Function&& f) -> cancel_token
361{
362 return at(clock_.now() + delay, std::forward<Function>(f));
363}
364
365inline void
367{
368 queue_.erase(token.iter_);
369}
370
371inline bool
373{
374 if (queue_.empty())
375 return false;
376 auto const iter = queue_.begin();
377 clock_.set(iter->when);
378 (*iter)();
379 queue_.erase(iter);
380 return true;
381}
382
383inline bool
385{
386 if (!step_one())
387 return false;
388 for (;;)
389 if (!step_one())
390 break;
391 return true;
392}
393
394template <class Function>
395inline bool
397{
398 bool ran = false;
399 while (f() && step_one())
400 ran = true;
401 return ran;
402}
403
404inline bool
406{
407 // VFALCO This routine needs optimizing
408 if (queue_.empty())
409 {
410 clock_.set(until);
411 return false;
412 }
413 auto iter = queue_.begin();
414 if (iter->when > until)
415 {
416 clock_.set(until);
417 return true;
418 }
419 do
420 {
421 step_one();
422 iter = queue_.begin();
423 } while (iter != queue_.end() && iter->when <= until);
424 clock_.set(until);
425 return iter != queue_.end();
426}
427
428template <class Period, class Rep>
429inline bool
431{
432 return step_until(now() + amount);
433}
434
435} // namespace csf
436} // namespace test
437} // namespace ripple
438
439#endif
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(time_point when_, DeducedHandler &&h)
event_impl & operator=(event_impl const &)=delete
event_impl(event_impl const &)=delete
typename boost::intrusive::make_multiset< event, boost::intrusive::constant_time_size< false > >::type by_when_set
queue_type(queue_type const &)=delete
by_when_set::iterator emplace(time_point when, Handler &&h)
queue_type & operator=(queue_type const &)=delete
boost::container::pmr::monotonic_buffer_resource * alloc_
Simulated discrete-event scheduler.
Scheduler & operator=(Scheduler const &)=delete
bool step_one()
Run the scheduler for up to one event.
bool step_while(Function &&func)
Run the scheduler while a condition is true.
typename clock_type::duration duration
cancel_token at(time_point const &when, Function &&f)
Schedule an event at a specific time.
typename clock_type::time_point time_point
bool step_for(std::chrono::duration< Period, Rep > const &amount)
Run the scheduler until time has elapsed.
boost::container::pmr::monotonic_buffer_resource alloc_
time_point now() const
Return the current network time.
bool step_until(time_point const &until)
Run the scheduler until the specified time.
clock_type & clock() const
Return the clock.
boost::intrusive::set_base_hook< boost::intrusive::link_mode< boost::intrusive::normal_link > > by_when_hook
Scheduler(Scheduler const &)=delete
void cancel(cancel_token const &token)
Cancel a timer.
bool step()
Run the scheduler until no events remain.
cancel_token in(duration const &delay, Function &&f)
Schedule an event after a specified duration passes.
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
constexpr auto kilobytes(T value) noexcept
STL namespace.
cancel_token & operator=(cancel_token const &)=default
cancel_token(typename queue_type::iterator iter)
cancel_token(cancel_token const &)=default
event & operator=(event const &)=delete
virtual void operator()() const =0
bool operator<(event const &other) const