blob: fc6492f4b4db8aadc9b8a6e2ddd748c8d28142a9 [file] [log] [blame]
Alexander Afanasyevf6468892014-01-29 01:04:14 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (C) 2014 Named Data Networking Project
4 * See COPYING for copyright and distribution information.
5 */
6
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -08007#include "common.hpp"
8
Alexander Afanasyevf6468892014-01-29 01:04:14 -08009#include "scheduler.hpp"
10
11namespace ndn {
12
13struct EventIdImpl
14{
15 EventIdImpl(const Scheduler::EventQueue::iterator& event)
16 : m_event(event)
17 , m_isValid(true)
18 {
19 }
20
21 void
22 invalidate()
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
45private:
46 Scheduler::EventQueue::iterator m_event;
47 bool m_isValid;
48};
49
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070050Scheduler::EventInfo::EventInfo(const time::nanoseconds& after,
51 const time::nanoseconds& period,
52 const Event& event)
53 : m_scheduledTime(time::steady_clock::now() + after)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080054 , m_period(period)
55 , m_event(event)
56{
57}
58
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070059Scheduler::EventInfo::EventInfo(const time::steady_clock::TimePoint& when, const EventInfo& previousEvent)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080060 : m_scheduledTime(when)
61 , m_period(previousEvent.m_period)
62 , m_event(previousEvent.m_event)
63 , m_eventId(previousEvent.m_eventId)
64{
65}
66
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070067time::nanoseconds
Alexander Afanasyevf6468892014-01-29 01:04:14 -080068Scheduler::EventInfo::expiresFromNow() const
69{
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070070 time::steady_clock::TimePoint now = time::steady_clock::now();
Alexander Afanasyevf6468892014-01-29 01:04:14 -080071 if (now > m_scheduledTime)
72 return time::seconds(0); // event should be scheduled ASAP
73 else
74 return m_scheduledTime - now;
75}
76
77
78Scheduler::Scheduler(boost::asio::io_service& ioService)
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070079 : m_scheduledEvent(m_events.end())
Alexander Afanasyevf6468892014-01-29 01:04:14 -080080 , m_deadlineTimer(ioService)
Yingdi Yuf2a82092014-02-03 16:49:15 -080081 , m_isEventExecuting(false)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080082{
83}
84
85EventId
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070086Scheduler::scheduleEvent(const time::nanoseconds& after,
Alexander Afanasyevf6468892014-01-29 01:04:14 -080087 const Event& event)
88{
89 return schedulePeriodicEvent(after, time::nanoseconds(-1), event);
90}
91
92EventId
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070093Scheduler::schedulePeriodicEvent(const time::nanoseconds& after,
94 const time::nanoseconds& period,
Alexander Afanasyevf6468892014-01-29 01:04:14 -080095 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));
Yingdi Yuf2a82092014-02-03 16:49:15 -080099
100 if (!m_isEventExecuting)
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800101 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800102 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 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800109 }
110
111 return i->m_eventId;
112}
113
114void
115Scheduler::cancelEvent(const EventId& eventId)
116{
Yingdi Yuab136552014-02-03 14:31:02 -0800117 if (!static_cast<bool>(eventId) || !eventId->isValid())
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800118 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
Yingdi Yuf2a82092014-02-03 16:49:15 -0800130 if (!m_isEventExecuting)
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800131 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800132 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 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800142 }
143}
144
145void
146Scheduler::onEvent(const boost::system::error_code& error)
147{
148 if (error) // e.g., cancelled
149 {
150 return;
151 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800152
153 m_isEventExecuting = true;
154
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800155 // process all expired events
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700156 time::steady_clock::TimePoint now = time::steady_clock::now();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800157 while(!m_events.empty() && m_events.begin()->m_scheduledTime <= now)
158 {
159 EventQueue::iterator head = m_events.begin();
160
Yingdi Yuf2a82092014-02-03 16:49:15 -0800161 Event event = head->m_event;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700162 if (head->m_period < time::nanoseconds::zero())
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800163 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800164 head->m_eventId->invalidate();
165 m_events.erase(head);
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800166 }
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);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800173 m_events.erase(head);
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800174 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800175
176 event();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800177 }
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));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800183 m_scheduledEvent = m_events.begin();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800184 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800185 else
186 {
187 m_scheduledEvent = m_events.end();
188 }
189
190 m_isEventExecuting = false;
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800191}
192
193
194} // namespace ndn