blob: 9a51871f1950f98c46c5c186e689a9cc524615c5 [file] [log] [blame]
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Alexander Afanasyevf6468892014-01-29 01:04:14 -08002/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
Alexander Afanasyevf6468892014-01-29 01:04:14 -080011 */
12
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080013#include "common.hpp"
14
Alexander Afanasyevf6468892014-01-29 01:04:14 -080015#include "scheduler.hpp"
16
17namespace ndn {
18
19struct EventIdImpl
20{
21 EventIdImpl(const Scheduler::EventQueue::iterator& event)
22 : m_event(event)
23 , m_isValid(true)
24 {
25 }
26
27 void
28 invalidate()
29 {
30 m_isValid = false;
31 }
32
33 bool
34 isValid() const
35 {
36 return m_isValid;
37 }
38
39 operator const Scheduler::EventQueue::iterator&() const
40 {
41 return m_event;
42 }
43
44 void
45 reset(const Scheduler::EventQueue::iterator& newIterator)
46 {
47 m_event = newIterator;
48 m_isValid = true;
49 }
50
51private:
52 Scheduler::EventQueue::iterator m_event;
53 bool m_isValid;
54};
55
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070056Scheduler::EventInfo::EventInfo(const time::nanoseconds& after,
57 const time::nanoseconds& period,
58 const Event& event)
59 : m_scheduledTime(time::steady_clock::now() + after)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080060 , m_period(period)
61 , m_event(event)
62{
63}
64
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070065Scheduler::EventInfo::EventInfo(const time::steady_clock::TimePoint& when, const EventInfo& previousEvent)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080066 : m_scheduledTime(when)
67 , m_period(previousEvent.m_period)
68 , m_event(previousEvent.m_event)
69 , m_eventId(previousEvent.m_eventId)
70{
71}
72
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070073time::nanoseconds
Alexander Afanasyevf6468892014-01-29 01:04:14 -080074Scheduler::EventInfo::expiresFromNow() const
75{
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070076 time::steady_clock::TimePoint now = time::steady_clock::now();
Alexander Afanasyevf6468892014-01-29 01:04:14 -080077 if (now > m_scheduledTime)
78 return time::seconds(0); // event should be scheduled ASAP
79 else
80 return m_scheduledTime - now;
81}
82
83
84Scheduler::Scheduler(boost::asio::io_service& ioService)
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070085 : m_scheduledEvent(m_events.end())
Alexander Afanasyevf6468892014-01-29 01:04:14 -080086 , m_deadlineTimer(ioService)
Yingdi Yuf2a82092014-02-03 16:49:15 -080087 , m_isEventExecuting(false)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080088{
89}
90
91EventId
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070092Scheduler::scheduleEvent(const time::nanoseconds& after,
Alexander Afanasyevf6468892014-01-29 01:04:14 -080093 const Event& event)
94{
95 return schedulePeriodicEvent(after, time::nanoseconds(-1), event);
96}
97
98EventId
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070099Scheduler::schedulePeriodicEvent(const time::nanoseconds& after,
100 const time::nanoseconds& period,
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800101 const Event& event)
102{
103 EventQueue::iterator i = m_events.insert(EventInfo(after, period, event));
104 i->m_eventId = make_shared<EventIdImpl>(boost::cref(i));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800105
106 if (!m_isEventExecuting)
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800107 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800108 if (m_scheduledEvent == m_events.end() ||
109 *i < *m_scheduledEvent)
110 {
111 m_deadlineTimer.expires_from_now(after);
112 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
113 m_scheduledEvent = i;
114 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800115 }
116
117 return i->m_eventId;
118}
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700119
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800120void
121Scheduler::cancelEvent(const EventId& eventId)
122{
Yingdi Yuab136552014-02-03 14:31:02 -0800123 if (!static_cast<bool>(eventId) || !eventId->isValid())
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800124 return; // event already fired or cancelled
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700125
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800126 if (static_cast<EventQueue::iterator>(*eventId) != m_scheduledEvent) {
127 m_events.erase(*eventId);
128 eventId->invalidate();
129 return;
130 }
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700131
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800132 m_deadlineTimer.cancel();
133 m_events.erase(static_cast<EventQueue::iterator>(*eventId));
134 eventId->invalidate();
135
Yingdi Yuf2a82092014-02-03 16:49:15 -0800136 if (!m_isEventExecuting)
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800137 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800138 if (!m_events.empty())
139 {
140 m_deadlineTimer.expires_from_now(m_events.begin()->expiresFromNow());
141 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
142 m_scheduledEvent = m_events.begin();
143 }
144 else
145 {
146 m_scheduledEvent = m_events.end();
147 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800148 }
149}
150
151void
152Scheduler::onEvent(const boost::system::error_code& error)
153{
154 if (error) // e.g., cancelled
155 {
156 return;
157 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800158
159 m_isEventExecuting = true;
160
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800161 // process all expired events
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700162 time::steady_clock::TimePoint now = time::steady_clock::now();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800163 while(!m_events.empty() && m_events.begin()->m_scheduledTime <= now)
164 {
165 EventQueue::iterator head = m_events.begin();
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700166
Yingdi Yuf2a82092014-02-03 16:49:15 -0800167 Event event = head->m_event;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700168 if (head->m_period < time::nanoseconds::zero())
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800169 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800170 head->m_eventId->invalidate();
171 m_events.erase(head);
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800172 }
173 else
174 {
175 // "reschedule" and update EventId data of the event
176 EventInfo event(now + head->m_period, *head);
177 EventQueue::iterator i = m_events.insert(event);
178 i->m_eventId->reset(i);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800179 m_events.erase(head);
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800180 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800181
182 event();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800183 }
184
185 if (!m_events.empty())
186 {
187 m_deadlineTimer.expires_from_now(m_events.begin()->m_scheduledTime - now);
188 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800189 m_scheduledEvent = m_events.begin();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800190 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800191 else
192 {
193 m_scheduledEvent = m_events.end();
194 }
195
196 m_isEventExecuting = false;
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800197}
198
199
200} // namespace ndn