blob: c13e070a3a240620fe3323afe83e618959313eee [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
7#include "scheduler.hpp"
8
9namespace ndn {
10
11struct EventIdImpl
12{
13 EventIdImpl(const Scheduler::EventQueue::iterator& event)
14 : m_event(event)
15 , m_isValid(true)
16 {
17 }
18
19 void
20 invalidate()
21 {
22 m_isValid = false;
23 }
24
25 bool
26 isValid() const
27 {
28 return m_isValid;
29 }
30
31 operator const Scheduler::EventQueue::iterator&() const
32 {
33 return m_event;
34 }
35
36 void
37 reset(const Scheduler::EventQueue::iterator& newIterator)
38 {
39 m_event = newIterator;
40 m_isValid = true;
41 }
42
43private:
44 Scheduler::EventQueue::iterator m_event;
45 bool m_isValid;
46};
47
48Scheduler::EventInfo::EventInfo(const time::Duration& after,
49 const time::Duration& period,
50 const Event& event)
51 : m_scheduledTime(time::now() + after)
52 , m_period(period)
53 , m_event(event)
54{
55}
56
57Scheduler::EventInfo::EventInfo(const time::Point& when, const EventInfo& previousEvent)
58 : m_scheduledTime(when)
59 , m_period(previousEvent.m_period)
60 , m_event(previousEvent.m_event)
61 , m_eventId(previousEvent.m_eventId)
62{
63}
64
65time::Duration
66Scheduler::EventInfo::expiresFromNow() const
67{
68 time::Point now = time::now();
69 if (now > m_scheduledTime)
70 return time::seconds(0); // event should be scheduled ASAP
71 else
72 return m_scheduledTime - now;
73}
74
75
76Scheduler::Scheduler(boost::asio::io_service& ioService)
77 : m_ioService(ioService)
78 , m_scheduledEvent(m_events.end())
79 , m_deadlineTimer(ioService)
Yingdi Yuf2a82092014-02-03 16:49:15 -080080 , m_isEventExecuting(false)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080081{
82}
83
84EventId
85Scheduler::scheduleEvent(const time::Duration& after,
86 const Event& event)
87{
88 return schedulePeriodicEvent(after, time::nanoseconds(-1), event);
89}
90
91EventId
92Scheduler::schedulePeriodicEvent(const time::Duration& after,
93 const time::Duration& period,
94 const Event& event)
95{
96 EventQueue::iterator i = m_events.insert(EventInfo(after, period, event));
97 i->m_eventId = make_shared<EventIdImpl>(boost::cref(i));
Yingdi Yuf2a82092014-02-03 16:49:15 -080098
99 if (!m_isEventExecuting)
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800100 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800101 if (m_scheduledEvent == m_events.end() ||
102 *i < *m_scheduledEvent)
103 {
104 m_deadlineTimer.expires_from_now(after);
105 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
106 m_scheduledEvent = i;
107 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800108 }
109
110 return i->m_eventId;
111}
112
113void
114Scheduler::cancelEvent(const EventId& eventId)
115{
Yingdi Yuab136552014-02-03 14:31:02 -0800116 if (!static_cast<bool>(eventId) || !eventId->isValid())
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800117 return; // event already fired or cancelled
118
119 if (static_cast<EventQueue::iterator>(*eventId) != m_scheduledEvent) {
120 m_events.erase(*eventId);
121 eventId->invalidate();
122 return;
123 }
124
125 m_deadlineTimer.cancel();
126 m_events.erase(static_cast<EventQueue::iterator>(*eventId));
127 eventId->invalidate();
128
Yingdi Yuf2a82092014-02-03 16:49:15 -0800129 if (!m_isEventExecuting)
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800130 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800131 if (!m_events.empty())
132 {
133 m_deadlineTimer.expires_from_now(m_events.begin()->expiresFromNow());
134 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
135 m_scheduledEvent = m_events.begin();
136 }
137 else
138 {
139 m_scheduledEvent = m_events.end();
140 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800141 }
142}
143
144void
145Scheduler::onEvent(const boost::system::error_code& error)
146{
147 if (error) // e.g., cancelled
148 {
149 return;
150 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800151
152 m_isEventExecuting = true;
153
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800154 // process all expired events
155 time::Point now = time::now();
156 while(!m_events.empty() && m_events.begin()->m_scheduledTime <= now)
157 {
158 EventQueue::iterator head = m_events.begin();
159
Yingdi Yuf2a82092014-02-03 16:49:15 -0800160 Event event = head->m_event;
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800161 if (head->m_period < 0)
162 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800163 head->m_eventId->invalidate();
164 m_events.erase(head);
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800165 }
166 else
167 {
168 // "reschedule" and update EventId data of the event
169 EventInfo event(now + head->m_period, *head);
170 EventQueue::iterator i = m_events.insert(event);
171 i->m_eventId->reset(i);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800172 m_events.erase(head);
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800173 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800174
175 event();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800176 }
177
178 if (!m_events.empty())
179 {
180 m_deadlineTimer.expires_from_now(m_events.begin()->m_scheduledTime - now);
181 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800182 m_scheduledEvent = m_events.begin();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800183 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800184 else
185 {
186 m_scheduledEvent = m_events.end();
187 }
188
189 m_isEventExecuting = false;
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800190}
191
192
193} // namespace ndn