rippled
test/csf/Scheduler.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2017 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED
21 #define RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED
22 
23 #include <ripple/basics/qalloc.h>
24 #include <ripple/beast/clock/manual_clock.h>
25 #include <boost/intrusive/set.hpp>
26 #include <type_traits>
27 #include <utility>
28 
29 namespace ripple {
30 namespace test {
31 namespace csf {
32 
44 class Scheduler
45 {
46 public:
48 
49  using duration = typename clock_type::duration;
50 
52 
53 private:
54  using by_when_hook = boost::intrusive::set_base_hook<
55  boost::intrusive::link_mode<boost::intrusive::normal_link>>;
56 
58  {
60 
61  event(event const&) = delete;
62  event&
63  operator=(event const&) = delete;
64 
65  virtual ~event() = default;
66 
67  // Called to perform the event
68  virtual void
69  operator()() const = 0;
70 
71  event(time_point when_) : when(when_)
72  {
73  }
74 
75  bool
76  operator<(event const& other) const
77  {
78  return when < other.when;
79  }
80  };
81 
82  template <class Handler>
83  class event_impl : public event
84  {
85  Handler const h_;
86 
87  public:
88  event_impl(event_impl const&) = delete;
89 
90  event_impl&
91  operator=(event_impl const&) = delete;
92 
93  template <class DeducedHandler>
94  event_impl(time_point when_, DeducedHandler&& h)
95  : event(when_), h_(std::forward<DeducedHandler>(h))
96  {
97  }
98 
99  void
100  operator()() const override
101  {
102  h_();
103  }
104  };
105 
107  {
108  private:
109  using by_when_set = typename boost::intrusive::make_multiset<
110  event,
111  boost::intrusive::constant_time_size<false>>::type;
112 
115 
116  public:
117  using iterator = typename by_when_set::iterator;
118 
119  queue_type(queue_type const&) = delete;
120  queue_type&
121  operator=(queue_type const&) = delete;
122 
123  explicit queue_type(qalloc const& alloc);
124 
125  ~queue_type();
126 
127  bool
128  empty() const;
129 
130  iterator
131  begin();
132 
133  iterator
134  end();
135 
136  template <class Handler>
137  typename by_when_set::iterator
138  emplace(time_point when, Handler&& h);
139 
140  iterator
141  erase(iterator iter);
142  };
143 
146 
147  // Aged containers that rely on this clock take a non-const reference =(
149 
150 public:
151  Scheduler(Scheduler const&) = delete;
152  Scheduler&
153  operator=(Scheduler const&) = delete;
154 
155  Scheduler();
156 
158  qalloc const&
159  alloc() const;
160 
162  clock_type&
163  clock() const;
164 
169  time_point
170  now() const;
171 
172  // Used to cancel timers
173  struct cancel_token;
174 
183  template <class Function>
185  at(time_point const& when, Function&& f);
186 
195  template <class Function>
197  in(duration const& delay, Function&& f);
198 
206  void
207  cancel(cancel_token const& token);
208 
218  bool
219  step_one();
220 
230  bool
231  step();
232 
246  template <class Function>
247  bool
248  step_while(Function&& func);
249 
259  bool
260  step_until(time_point const& until);
261 
271  template <class Period, class Rep>
272  bool
274 };
275 
276 //------------------------------------------------------------------------------
277 
278 inline Scheduler::queue_type::queue_type(qalloc const& alloc) : alloc_(alloc)
279 {
280 }
281 
283 {
284  for (auto iter = by_when_.begin(); iter != by_when_.end();)
285  {
286  auto e = &*iter;
287  ++iter;
288  e->~event();
289  alloc_.dealloc(e, 1);
290  }
291 }
292 
293 inline bool
295 {
296  return by_when_.empty();
297 }
298 
299 inline auto
301 {
302  return by_when_.begin();
303 }
304 
305 inline auto
307 {
308  return by_when_.end();
309 }
310 
311 template <class Handler>
312 inline auto
314  typename by_when_set::iterator
315 {
316  using event_type = event_impl<std::decay_t<Handler>>;
317  auto const p = alloc_.alloc<event_type>(1);
318  auto& e = *new (p) event_type(when, std::forward<Handler>(h));
319  return by_when_.insert(e);
320 }
321 
322 inline auto
323 Scheduler::queue_type::erase(iterator iter) -> typename by_when_set::iterator
324 {
325  auto& e = *iter;
326  auto next = by_when_.erase(iter);
327  e.~event();
328  alloc_.dealloc(&e, 1);
329  return next;
330 }
331 
332 //-----------------------------------------------------------------------------
334 {
335 private:
337 
338 public:
339  cancel_token() = delete;
340  cancel_token(cancel_token const&) = default;
341  cancel_token&
342  operator=(cancel_token const&) = default;
343 
344 private:
345  friend class Scheduler;
346  cancel_token(typename queue_type::iterator iter) : iter_(iter)
347  {
348  }
349 };
350 
351 //------------------------------------------------------------------------------
353 {
354 }
355 
356 inline qalloc const&
358 {
359  return alloc_;
360 }
361 
362 inline auto
364 {
365  return clock_;
366 }
367 
368 inline auto
370 {
371  return clock_.now();
372 }
373 
374 template <class Function>
375 inline auto
376 Scheduler::at(time_point const& when, Function&& f) -> cancel_token
377 {
378  return queue_.emplace(when, std::forward<Function>(f));
379 }
380 
381 template <class Function>
382 inline auto
383 Scheduler::in(duration const& delay, Function&& f) -> cancel_token
384 {
385  return at(clock_.now() + delay, std::forward<Function>(f));
386 }
387 
388 inline void
390 {
391  queue_.erase(token.iter_);
392 }
393 
394 inline bool
396 {
397  if (queue_.empty())
398  return false;
399  auto const iter = queue_.begin();
400  clock_.set(iter->when);
401  (*iter)();
402  queue_.erase(iter);
403  return true;
404 }
405 
406 inline bool
408 {
409  if (!step_one())
410  return false;
411  for (;;)
412  if (!step_one())
413  break;
414  return true;
415 }
416 
417 template <class Function>
418 inline bool
420 {
421  bool ran = false;
422  while (f() && step_one())
423  ran = true;
424  return ran;
425 }
426 
427 inline bool
429 {
430  // VFALCO This routine needs optimizing
431  if (queue_.empty())
432  {
433  clock_.set(until);
434  return false;
435  }
436  auto iter = queue_.begin();
437  if (iter->when > until)
438  {
439  clock_.set(until);
440  return true;
441  }
442  do
443  {
444  step_one();
445  iter = queue_.begin();
446  } while (iter != queue_.end() && iter->when <= until);
447  clock_.set(until);
448  return iter != queue_.end();
449 }
450 
451 template <class Period, class Rep>
452 inline bool
454 {
455  return step_until(now() + amount);
456 }
457 
458 } // namespace csf
459 } // namespace test
460 } // namespace ripple
461 
462 #endif
ripple::test::csf::Scheduler::queue_type::queue_type
queue_type(queue_type const &)=delete
utility
ripple::test::csf::Scheduler::queue_type::emplace
by_when_set::iterator emplace(time_point when, Handler &&h)
ripple::test::csf::Scheduler::event::event
event(event const &)=delete
ripple::test::csf::Scheduler::cancel
void cancel(cancel_token const &token)
Cancel a timer.
Definition: test/csf/Scheduler.h:389
ripple::test::csf::Scheduler::event::operator=
event & operator=(event const &)=delete
ripple::test::csf::Scheduler::queue_type::end
iterator end()
Definition: test/csf/Scheduler.h:306
ripple::test::csf::Scheduler::step_while
bool step_while(Function &&func)
Run the scheduler while a condition is true.
Definition: test/csf/Scheduler.h:419
ripple::test::csf::Scheduler::clock
clock_type & clock() const
Return the clock.
Definition: test/csf/Scheduler.h:363
ripple::test::csf::Scheduler
Simulated discrete-event scheduler.
Definition: test/csf/Scheduler.h:44
std::chrono::duration
ripple::test::csf::Scheduler::alloc
qalloc const & alloc() const
Return the allocator.
Definition: test/csf/Scheduler.h:357
beast::manual_clock::set
void set(time_point const &when)
Set the current time of the manual clock.
Definition: manual_clock.h:62
ripple::test::csf::Scheduler::time_point
typename clock_type::time_point time_point
Definition: test/csf/Scheduler.h:51
ripple::test::csf::Scheduler::queue_type::iterator
typename by_when_set::iterator iterator
Definition: test/csf/Scheduler.h:117
ripple::test::csf::Scheduler::queue_type
Definition: test/csf/Scheduler.h:106
ripple::test::csf::Scheduler::queue_type::operator=
queue_type & operator=(queue_type const &)=delete
ripple::qalloc_type< int, true >
ripple::test::csf::Scheduler::cancel_token::iter_
queue_type::iterator iter_
Definition: test/csf/Scheduler.h:336
ripple::qalloc_type::alloc
U * alloc(std::size_t n)
Definition: qalloc.h:302
ripple::test::csf::Scheduler::event_impl::event_impl
event_impl(time_point when_, DeducedHandler &&h)
Definition: test/csf/Scheduler.h:94
ripple::test::csf::Scheduler::step_one
bool step_one()
Run the scheduler for up to one event.
Definition: test/csf/Scheduler.h:395
ripple::test::csf::Scheduler::cancel_token
Definition: test/csf/Scheduler.h:333
ripple::test::csf::Scheduler::alloc_
qalloc alloc_
Definition: test/csf/Scheduler.h:144
ripple::test::csf::Scheduler::in
cancel_token in(duration const &delay, Function &&f)
Schedule an event after a specified duration passes.
ripple::test::csf::Scheduler::queue_type::erase
iterator erase(iterator iter)
Definition: test/csf/Scheduler.h:323
ripple::test::csf::Scheduler::duration
typename clock_type::duration duration
Definition: test/csf/Scheduler.h:49
ripple::test::csf::Scheduler::event::operator<
bool operator<(event const &other) const
Definition: test/csf/Scheduler.h:76
ripple::test::csf::Scheduler::by_when_hook
boost::intrusive::set_base_hook< boost::intrusive::link_mode< boost::intrusive::normal_link > > by_when_hook
Definition: test/csf/Scheduler.h:55
ripple::test::csf::Scheduler::event_impl::h_
const Handler h_
Definition: test/csf/Scheduler.h:85
ripple::test::csf::Scheduler::cancel_token::cancel_token
cancel_token(typename queue_type::iterator iter)
Definition: test/csf/Scheduler.h:346
ripple::test::csf::Scheduler::queue_type::begin
iterator begin()
Definition: test/csf/Scheduler.h:300
ripple::test::csf::Scheduler::Scheduler
Scheduler()
Definition: test/csf/Scheduler.h:352
ripple::test::csf::Scheduler::queue_type::empty
bool empty() const
Definition: test/csf/Scheduler.h:294
ripple::test::csf::Scheduler::event_impl::operator=
event_impl & operator=(event_impl const &)=delete
ripple::test::csf::Scheduler::event::event
event(time_point when_)
Definition: test/csf/Scheduler.h:71
ripple::test::csf::Scheduler::event_impl
Definition: test/csf/Scheduler.h:83
ripple::test::csf::Scheduler::event_impl::operator()
void operator()() const override
Definition: test/csf/Scheduler.h:100
ripple::test::csf::Scheduler::step_until
bool step_until(time_point const &until)
Run the scheduler until the specified time.
Definition: test/csf/Scheduler.h:428
ripple::qalloc_type::dealloc
void dealloc(U *p, std::size_t n)
Definition: qalloc.h:313
ripple::test::csf::Scheduler::queue_
queue_type queue_
Definition: test/csf/Scheduler.h:145
beast::manual_clock::now
time_point now() const override
Returns the current time.
Definition: manual_clock.h:55
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::csf::Scheduler::at
cancel_token at(time_point const &when, Function &&f)
Schedule an event at a specific time.
ripple::test::csf::Scheduler::queue_type::by_when_
by_when_set by_when_
Definition: test/csf/Scheduler.h:114
ripple::test::csf::Scheduler::step
bool step()
Run the scheduler until no events remain.
Definition: test/csf/Scheduler.h:407
ripple::test::csf::Scheduler::event
Definition: test/csf/Scheduler.h:57
std
STL namespace.
ripple::test::csf::Scheduler::event::~event
virtual ~event()=default
ripple::test::csf::Scheduler::queue_type::~queue_type
~queue_type()
Definition: test/csf/Scheduler.h:282
ripple::test::csf::Scheduler::event::operator()
virtual void operator()() const =0
ripple::test::csf::Scheduler::queue_type::by_when_set
typename boost::intrusive::make_multiset< event, boost::intrusive::constant_time_size< false > >::type by_when_set
Definition: test/csf/Scheduler.h:111
ripple::test::csf::Scheduler::queue_type::alloc_
qalloc alloc_
Definition: test/csf/Scheduler.h:113
ripple::test::csf::Scheduler::operator=
Scheduler & operator=(Scheduler const &)=delete
beast::manual_clock< std::chrono::steady_clock >
ripple::test::csf::Scheduler::clock_
clock_type clock_
Definition: test/csf/Scheduler.h:148
ripple::test::csf::Scheduler::now
time_point now() const
Return the current network time.
Definition: test/csf/Scheduler.h:369
ripple::test::csf::Scheduler::step_for
bool step_for(std::chrono::duration< Period, Rep > const &amount)
Run the scheduler until time has elapsed.
Definition: test/csf/Scheduler.h:453
beast::abstract_clock< std::chrono::steady_clock >::time_point
typename std::chrono::steady_clock ::time_point time_point
Definition: abstract_clock.h:63
ripple::test::csf::Scheduler::event::when
time_point when
Definition: test/csf/Scheduler.h:59
type_traits
beast::abstract_clock< std::chrono::steady_clock >::duration
typename std::chrono::steady_clock ::duration duration
Definition: abstract_clock.h:62
ripple::test::csf::Scheduler::event_impl::event_impl
event_impl(event_impl const &)=delete