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_)
96  , h_(std::forward<DeducedHandler>(h))
97  {
98  }
99 
100  void
101  operator()() const override
102  {
103  h_();
104  }
105  };
106 
108  {
109  private:
110  using by_when_set = typename boost::intrusive::make_multiset<
111  event,
112  boost::intrusive::constant_time_size<false>>::type;
113 
116 
117  public:
118  using iterator = typename by_when_set::iterator;
119 
120  queue_type(queue_type const&) = delete;
121  queue_type&
122  operator=(queue_type const&) = delete;
123 
124  explicit queue_type(qalloc const& alloc);
125 
126  ~queue_type();
127 
128  bool
129  empty() const;
130 
131  iterator
132  begin();
133 
134  iterator
135  end();
136 
137  template <class Handler>
138  typename by_when_set::iterator
139  emplace(time_point when, Handler&& h);
140 
141  iterator
142  erase(iterator iter);
143  };
144 
147 
148  // Aged containers that rely on this clock take a non-const reference =(
150 
151 public:
152  Scheduler(Scheduler const&) = delete;
153  Scheduler&
154  operator=(Scheduler const&) = delete;
155 
156  Scheduler();
157 
159  qalloc const&
160  alloc() const;
161 
163  clock_type &
164  clock() const;
165 
170  time_point
171  now() const;
172 
173  // Used to cancel timers
174  struct cancel_token;
175 
184  template <class Function>
186  at(time_point const& when, Function&& f);
187 
196  template <class Function>
198  in(duration const& delay, Function&& f);
199 
207  void
208  cancel(cancel_token const& token);
209 
219  bool
220  step_one();
221 
231  bool
232  step();
233 
247  template <class Function>
248  bool
249  step_while(Function&& func);
250 
260  bool
261  step_until(time_point const& until);
262 
272  template <class Period, class Rep>
273  bool
275 };
276 
277 //------------------------------------------------------------------------------
278 
279 inline Scheduler::queue_type::queue_type(qalloc const& alloc) : alloc_(alloc)
280 {
281 }
282 
284 {
285  for (auto iter = by_when_.begin(); iter != by_when_.end();)
286  {
287  auto e = &*iter;
288  ++iter;
289  e->~event();
290  alloc_.dealloc(e, 1);
291  }
292 }
293 
294 inline bool
296 {
297  return by_when_.empty();
298 }
299 
300 inline auto
302 {
303  return by_when_.begin();
304 }
305 
306 inline auto
308 {
309  return by_when_.end();
310 }
311 
312 
313 template <class Handler>
314 inline auto
316  typename by_when_set::iterator
317 {
318  using event_type = event_impl<std::decay_t<Handler>>;
319  auto const p = alloc_.alloc<event_type>(1);
320  auto& e = *new (p) event_type(
321  when, std::forward<Handler>(h));
322  return by_when_.insert(e);
323 }
324 
325 inline auto
326 Scheduler::queue_type::erase(iterator iter) -> typename by_when_set::iterator
327 {
328  auto& e = *iter;
329  auto next = by_when_.erase(iter);
330  e.~event();
331  alloc_.dealloc(&e, 1);
332  return next;
333 }
334 
335 //-----------------------------------------------------------------------------
337 {
338 private:
340 
341 public:
342  cancel_token() = delete;
343  cancel_token(cancel_token const&) = default;
344  cancel_token&
345  operator=(cancel_token const&) = default;
346 
347 private:
348  friend class Scheduler;
349  cancel_token(typename queue_type::iterator iter) : iter_(iter)
350  {
351  }
352 };
353 
354 //------------------------------------------------------------------------------
356 {
357 }
358 
359 inline qalloc const&
361 {
362  return alloc_;
363 }
364 
365 inline auto
367 {
368  return clock_;
369 }
370 
371 inline auto
373 {
374  return clock_.now();
375 }
376 
377 template <class Function>
378 inline auto
379 Scheduler::at(time_point const& when, Function&& f) -> cancel_token
380 {
381  return queue_.emplace(when, std::forward<Function>(f));
382 }
383 
384 template <class Function>
385 inline auto
386 Scheduler::in(duration const& delay, Function&& f) -> cancel_token
387 {
388  return at(clock_.now() + delay, std::forward<Function>(f));
389 }
390 
391 inline void
393 {
394  queue_.erase(token.iter_);
395 }
396 
397 inline bool
399 {
400  if (queue_.empty())
401  return false;
402  auto const iter = queue_.begin();
403  clock_.set(iter->when);
404  (*iter)();
405  queue_.erase(iter);
406  return true;
407 }
408 
409 inline bool
411 {
412  if (!step_one())
413  return false;
414  for (;;)
415  if (!step_one())
416  break;
417  return true;
418 }
419 
420 template <class Function>
421 inline bool
423 {
424  bool ran = false;
425  while (f() && step_one())
426  ran = true;
427  return ran;
428 }
429 
430 inline bool
432 {
433  // VFALCO This routine needs optimizing
434  if (queue_.empty())
435  {
436  clock_.set(until);
437  return false;
438  }
439  auto iter = queue_.begin();
440  if (iter->when > until)
441  {
442  clock_.set(until);
443  return true;
444  }
445  do
446  {
447  step_one();
448  iter = queue_.begin();
449  } while (iter != queue_.end() && iter->when <= until);
450  clock_.set(until);
451  return iter != queue_.end();
452 }
453 
454 template <class Period, class Rep>
455 inline bool
457 {
458  return step_until(now() + amount);
459 }
460 
461 } // namespace csf
462 } // namespace test
463 } // namespace ripple
464 
465 #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:392
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:307
ripple::test::csf::Scheduler::step_while
bool step_while(Function &&func)
Run the scheduler while a condition is true.
Definition: test/csf/Scheduler.h:422
ripple::test::csf::Scheduler::clock
clock_type & clock() const
Return the clock.
Definition: test/csf/Scheduler.h:366
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:360
beast::manual_clock::set
void set(time_point const &when)
Set the current time of the manual clock.
Definition: manual_clock.h:64
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:118
ripple::test::csf::Scheduler::queue_type
Definition: test/csf/Scheduler.h:107
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:339
ripple::qalloc_type::alloc
U * alloc(std::size_t n)
Definition: qalloc.h:322
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:398
ripple::test::csf::Scheduler::cancel_token
Definition: test/csf/Scheduler.h:336
ripple::test::csf::Scheduler::alloc_
qalloc alloc_
Definition: test/csf/Scheduler.h:145
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:326
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:349
ripple::test::csf::Scheduler::queue_type::begin
iterator begin()
Definition: test/csf/Scheduler.h:301
ripple::test::csf::Scheduler::Scheduler
Scheduler()
Definition: test/csf/Scheduler.h:355
ripple::test::csf::Scheduler::queue_type::empty
bool empty() const
Definition: test/csf/Scheduler.h:295
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:101
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:431
ripple::qalloc_type::dealloc
void dealloc(U *p, std::size_t n)
Definition: qalloc.h:337
ripple::test::csf::Scheduler::queue_
queue_type queue_
Definition: test/csf/Scheduler.h:146
beast::manual_clock::now
time_point now() const override
Returns the current time.
Definition: manual_clock.h:57
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:115
ripple::test::csf::Scheduler::step
bool step()
Run the scheduler until no events remain.
Definition: test/csf/Scheduler.h:410
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:283
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:112
ripple::test::csf::Scheduler::queue_type::alloc_
qalloc alloc_
Definition: test/csf/Scheduler.h:114
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:149
ripple::test::csf::Scheduler::now
time_point now() const
Return the current network time.
Definition: test/csf/Scheduler.h:372
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:456
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