blob: 13a6c3a753c7ab605f734554e9087644b58a9742 [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)
80{
81}
82
83EventId
84Scheduler::scheduleEvent(const time::Duration& after,
85 const Event& event)
86{
87 return schedulePeriodicEvent(after, time::nanoseconds(-1), event);
88}
89
90EventId
91Scheduler::schedulePeriodicEvent(const time::Duration& after,
92 const time::Duration& period,
93 const Event& event)
94{
95 EventQueue::iterator i = m_events.insert(EventInfo(after, period, event));
96 i->m_eventId = make_shared<EventIdImpl>(boost::cref(i));
97
98 if (m_scheduledEvent == m_events.end() ||
99 *i < *m_scheduledEvent)
100 {
101 m_deadlineTimer.expires_from_now(after);
102 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
103 m_scheduledEvent = i;
104 }
105
106 return i->m_eventId;
107}
108
109void
110Scheduler::cancelEvent(const EventId& eventId)
111{
Yingdi Yuab136552014-02-03 14:31:02 -0800112 if (!static_cast<bool>(eventId) || !eventId->isValid())
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800113 return; // event already fired or cancelled
114
115 if (static_cast<EventQueue::iterator>(*eventId) != m_scheduledEvent) {
116 m_events.erase(*eventId);
117 eventId->invalidate();
118 return;
119 }
120
121 m_deadlineTimer.cancel();
122 m_events.erase(static_cast<EventQueue::iterator>(*eventId));
123 eventId->invalidate();
124
125 if (!m_events.empty())
126 {
127 m_deadlineTimer.expires_from_now(m_events.begin()->expiresFromNow());
128 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
129 m_scheduledEvent = m_events.begin();
130 }
131 else
132 {
133 m_deadlineTimer.cancel();
134 m_scheduledEvent = m_events.end();
135 }
136}
137
138void
139Scheduler::onEvent(const boost::system::error_code& error)
140{
141 if (error) // e.g., cancelled
142 {
143 return;
144 }
145
146 // process all expired events
147 time::Point now = time::now();
148 while(!m_events.empty() && m_events.begin()->m_scheduledTime <= now)
149 {
150 EventQueue::iterator head = m_events.begin();
151
152 head->m_event();
153 if (head->m_period < 0)
154 {
Yingdi Yuab136552014-02-03 14:31:02 -0800155 if(head->m_eventId->isValid())
156 {
157 head->m_eventId->invalidate();
158 m_events.erase(head);
159 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800160 }
161 else
162 {
Yingdi Yuab136552014-02-03 14:31:02 -0800163 bool validity = head->m_eventId->isValid();
164
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800165 // "reschedule" and update EventId data of the event
166 EventInfo event(now + head->m_period, *head);
167 EventQueue::iterator i = m_events.insert(event);
168 i->m_eventId->reset(i);
Yingdi Yuab136552014-02-03 14:31:02 -0800169 if(validity)
170 m_events.erase(head);
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800171 }
172 }
173
174 if (!m_events.empty())
175 {
176 m_deadlineTimer.expires_from_now(m_events.begin()->m_scheduledTime - now);
177 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
178 }
179}
180
181
182} // namespace ndn