blob: c2f55640b76cfe522132c8bff5c4e0c808de1b34 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevf6468892014-01-29 01:04:14 -08002/**
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -08003 * Copyright (c) 2013-2015 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyevf6468892014-01-29 01:04:14 -080020 */
21
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080022#include "common.hpp"
23
Alexander Afanasyevf6468892014-01-29 01:04:14 -080024#include "scheduler.hpp"
25
26namespace ndn {
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -080027namespace util {
28namespace scheduler {
Alexander Afanasyevf6468892014-01-29 01:04:14 -080029
30struct EventIdImpl
31{
32 EventIdImpl(const Scheduler::EventQueue::iterator& event)
33 : m_event(event)
34 , m_isValid(true)
35 {
36 }
37
38 void
39 invalidate()
40 {
41 m_isValid = false;
42 }
43
44 bool
45 isValid() const
46 {
47 return m_isValid;
48 }
49
50 operator const Scheduler::EventQueue::iterator&() const
51 {
52 return m_event;
53 }
54
55 void
56 reset(const Scheduler::EventQueue::iterator& newIterator)
57 {
58 m_event = newIterator;
59 m_isValid = true;
60 }
61
62private:
63 Scheduler::EventQueue::iterator m_event;
64 bool m_isValid;
65};
66
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070067Scheduler::EventInfo::EventInfo(const time::nanoseconds& after,
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070068 const Event& event)
69 : m_scheduledTime(time::steady_clock::now() + after)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080070 , m_event(event)
71{
72}
73
Alexander Afanasyevb67090a2014-04-29 22:31:01 -070074Scheduler::EventInfo::EventInfo(const time::steady_clock::TimePoint& when,
75 const EventInfo& previousEvent)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080076 : m_scheduledTime(when)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080077 , m_event(previousEvent.m_event)
78 , m_eventId(previousEvent.m_eventId)
79{
80}
81
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070082time::nanoseconds
Alexander Afanasyevf6468892014-01-29 01:04:14 -080083Scheduler::EventInfo::expiresFromNow() const
84{
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070085 time::steady_clock::TimePoint now = time::steady_clock::now();
Alexander Afanasyevf6468892014-01-29 01:04:14 -080086 if (now > m_scheduledTime)
87 return time::seconds(0); // event should be scheduled ASAP
88 else
89 return m_scheduledTime - now;
90}
91
92
93Scheduler::Scheduler(boost::asio::io_service& ioService)
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070094 : m_scheduledEvent(m_events.end())
Alexander Afanasyevf6468892014-01-29 01:04:14 -080095 , m_deadlineTimer(ioService)
Yingdi Yuf2a82092014-02-03 16:49:15 -080096 , m_isEventExecuting(false)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080097{
98}
99
100EventId
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700101Scheduler::scheduleEvent(const time::nanoseconds& after,
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800102 const Event& event)
103{
Alexander Afanasyev72a11782014-06-19 13:46:57 -0700104 EventQueue::iterator i = m_events.insert(EventInfo(after, event));
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700105
106 // On OSX 10.9, boost, and C++03 the following doesn't work without ndn::
107 // because the argument-dependent lookup prefers STL to boost
108 i->m_eventId = ndn::make_shared<EventIdImpl>(i);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800109
110 if (!m_isEventExecuting)
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800111 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800112 if (m_scheduledEvent == m_events.end() ||
113 *i < *m_scheduledEvent)
114 {
115 m_deadlineTimer.expires_from_now(after);
116 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
117 m_scheduledEvent = i;
118 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800119 }
120
121 return i->m_eventId;
122}
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700123
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800124void
125Scheduler::cancelEvent(const EventId& eventId)
126{
Yingdi Yuab136552014-02-03 14:31:02 -0800127 if (!static_cast<bool>(eventId) || !eventId->isValid())
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800128 return; // event already fired or cancelled
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700129
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800130 if (static_cast<EventQueue::iterator>(*eventId) != m_scheduledEvent) {
131 m_events.erase(*eventId);
132 eventId->invalidate();
133 return;
134 }
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700135
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800136 m_deadlineTimer.cancel();
137 m_events.erase(static_cast<EventQueue::iterator>(*eventId));
138 eventId->invalidate();
139
Yingdi Yuf2a82092014-02-03 16:49:15 -0800140 if (!m_isEventExecuting)
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800141 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800142 if (!m_events.empty())
143 {
144 m_deadlineTimer.expires_from_now(m_events.begin()->expiresFromNow());
145 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
146 m_scheduledEvent = m_events.begin();
147 }
148 else
149 {
150 m_scheduledEvent = m_events.end();
151 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800152 }
153}
154
155void
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700156Scheduler::cancelAllEvents()
157{
158 m_events.clear();
159 m_deadlineTimer.cancel();
160}
161
162void
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800163Scheduler::onEvent(const boost::system::error_code& error)
164{
165 if (error) // e.g., cancelled
166 {
167 return;
168 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800169
170 m_isEventExecuting = true;
171
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800172 // process all expired events
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700173 time::steady_clock::TimePoint now = time::steady_clock::now();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800174 while(!m_events.empty() && m_events.begin()->m_scheduledTime <= now)
175 {
176 EventQueue::iterator head = m_events.begin();
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700177
Yingdi Yuf2a82092014-02-03 16:49:15 -0800178 Event event = head->m_event;
Alexander Afanasyev72a11782014-06-19 13:46:57 -0700179 head->m_eventId->invalidate();
180 m_events.erase(head);
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
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800200} // namespace scheduler
201} // namespace util
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800202} // namespace ndn