All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
scheduler.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
7 #include "common.hpp"
8 
9 #include "scheduler.hpp"
10 
11 namespace ndn {
12 
14 {
15  EventIdImpl(const Scheduler::EventQueue::iterator& event)
16  : m_event(event)
17  , m_isValid(true)
18  {
19  }
20 
21  void
23  {
24  m_isValid = false;
25  }
26 
27  bool
28  isValid() const
29  {
30  return m_isValid;
31  }
32 
33  operator const Scheduler::EventQueue::iterator&() const
34  {
35  return m_event;
36  }
37 
38  void
39  reset(const Scheduler::EventQueue::iterator& newIterator)
40  {
41  m_event = newIterator;
42  m_isValid = true;
43  }
44 
45 private:
46  Scheduler::EventQueue::iterator m_event;
47  bool m_isValid;
48 };
49 
50 Scheduler::EventInfo::EventInfo(const time::nanoseconds& after,
51  const time::nanoseconds& period,
52  const Event& event)
53  : m_scheduledTime(time::steady_clock::now() + after)
54  , m_period(period)
55  , m_event(event)
56 {
57 }
58 
59 Scheduler::EventInfo::EventInfo(const time::steady_clock::TimePoint& when, const EventInfo& previousEvent)
60  : m_scheduledTime(when)
61  , m_period(previousEvent.m_period)
62  , m_event(previousEvent.m_event)
63  , m_eventId(previousEvent.m_eventId)
64 {
65 }
66 
67 time::nanoseconds
68 Scheduler::EventInfo::expiresFromNow() const
69 {
70  time::steady_clock::TimePoint now = time::steady_clock::now();
71  if (now > m_scheduledTime)
72  return time::seconds(0); // event should be scheduled ASAP
73  else
74  return m_scheduledTime - now;
75 }
76 
77 
78 Scheduler::Scheduler(boost::asio::io_service& ioService)
79  : m_scheduledEvent(m_events.end())
80  , m_deadlineTimer(ioService)
81  , m_isEventExecuting(false)
82 {
83 }
84 
85 EventId
86 Scheduler::scheduleEvent(const time::nanoseconds& after,
87  const Event& event)
88 {
89  return schedulePeriodicEvent(after, time::nanoseconds(-1), event);
90 }
91 
92 EventId
93 Scheduler::schedulePeriodicEvent(const time::nanoseconds& after,
94  const time::nanoseconds& period,
95  const Event& event)
96 {
97  EventQueue::iterator i = m_events.insert(EventInfo(after, period, event));
98  i->m_eventId = make_shared<EventIdImpl>(boost::cref(i));
99 
100  if (!m_isEventExecuting)
101  {
102  if (m_scheduledEvent == m_events.end() ||
103  *i < *m_scheduledEvent)
104  {
105  m_deadlineTimer.expires_from_now(after);
106  m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
107  m_scheduledEvent = i;
108  }
109  }
110 
111  return i->m_eventId;
112 }
113 
114 void
116 {
117  if (!static_cast<bool>(eventId) || !eventId->isValid())
118  return; // event already fired or cancelled
119 
120  if (static_cast<EventQueue::iterator>(*eventId) != m_scheduledEvent) {
121  m_events.erase(*eventId);
122  eventId->invalidate();
123  return;
124  }
125 
126  m_deadlineTimer.cancel();
127  m_events.erase(static_cast<EventQueue::iterator>(*eventId));
128  eventId->invalidate();
129 
130  if (!m_isEventExecuting)
131  {
132  if (!m_events.empty())
133  {
134  m_deadlineTimer.expires_from_now(m_events.begin()->expiresFromNow());
135  m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
136  m_scheduledEvent = m_events.begin();
137  }
138  else
139  {
140  m_scheduledEvent = m_events.end();
141  }
142  }
143 }
144 
145 void
146 Scheduler::onEvent(const boost::system::error_code& error)
147 {
148  if (error) // e.g., cancelled
149  {
150  return;
151  }
152 
153  m_isEventExecuting = true;
154 
155  // process all expired events
156  time::steady_clock::TimePoint now = time::steady_clock::now();
157  while(!m_events.empty() && m_events.begin()->m_scheduledTime <= now)
158  {
159  EventQueue::iterator head = m_events.begin();
160 
161  Event event = head->m_event;
162  if (head->m_period < time::nanoseconds::zero())
163  {
164  head->m_eventId->invalidate();
165  m_events.erase(head);
166  }
167  else
168  {
169  // "reschedule" and update EventId data of the event
170  EventInfo event(now + head->m_period, *head);
171  EventQueue::iterator i = m_events.insert(event);
172  i->m_eventId->reset(i);
173  m_events.erase(head);
174  }
175 
176  event();
177  }
178 
179  if (!m_events.empty())
180  {
181  m_deadlineTimer.expires_from_now(m_events.begin()->m_scheduledTime - now);
182  m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
183  m_scheduledEvent = m_events.begin();
184  }
185  else
186  {
187  m_scheduledEvent = m_events.end();
188  }
189 
190  m_isEventExecuting = false;
191 }
192 
193 
194 } // namespace ndn
time_point TimePoint
Definition: time.hpp:84
function< void()> Event
Definition: scheduler.hpp:27
EventId scheduleEvent(const time::nanoseconds &after, const Event &event)
Schedule one time event after the specified delay.
Definition: scheduler.cpp:86
void reset(const Scheduler::EventQueue::iterator &newIterator)
Definition: scheduler.cpp:39
shared_ptr< EventIdImpl > EventId
Private storage of information about the event.
Definition: scheduler.hpp:15
EventIdImpl(const Scheduler::EventQueue::iterator &event)
Definition: scheduler.cpp:15
void cancelEvent(const EventId &eventId)
Cancel scheduled event.
Definition: scheduler.cpp:115
Scheduler(boost::asio::io_service &ioService)
Definition: scheduler.cpp:78
bool isValid() const
Definition: scheduler.cpp:28
EventId schedulePeriodicEvent(const time::nanoseconds &after, const time::nanoseconds &period, const Event &event)
Schedule periodic event that should be fired every specified period.
Definition: scheduler.cpp:93