blob: 4e74d102d25d05e82836472a023a279a6a58d67b [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 Afanasyevb67090a2014-04-29 22:31:01 -070065Scheduler::EventInfo::EventInfo(const time::steady_clock::TimePoint& when,
66 const EventInfo& previousEvent)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080067 : m_scheduledTime(when)
68 , m_period(previousEvent.m_period)
69 , m_event(previousEvent.m_event)
70 , m_eventId(previousEvent.m_eventId)
71{
72}
73
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070074time::nanoseconds
Alexander Afanasyevf6468892014-01-29 01:04:14 -080075Scheduler::EventInfo::expiresFromNow() const
76{
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070077 time::steady_clock::TimePoint now = time::steady_clock::now();
Alexander Afanasyevf6468892014-01-29 01:04:14 -080078 if (now > m_scheduledTime)
79 return time::seconds(0); // event should be scheduled ASAP
80 else
81 return m_scheduledTime - now;
82}
83
84
85Scheduler::Scheduler(boost::asio::io_service& ioService)
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070086 : m_scheduledEvent(m_events.end())
Alexander Afanasyevf6468892014-01-29 01:04:14 -080087 , m_deadlineTimer(ioService)
Yingdi Yuf2a82092014-02-03 16:49:15 -080088 , m_isEventExecuting(false)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080089{
90}
91
92EventId
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070093Scheduler::scheduleEvent(const time::nanoseconds& after,
Alexander Afanasyevf6468892014-01-29 01:04:14 -080094 const Event& event)
95{
96 return schedulePeriodicEvent(after, time::nanoseconds(-1), event);
97}
98
99EventId
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700100Scheduler::schedulePeriodicEvent(const time::nanoseconds& after,
101 const time::nanoseconds& period,
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800102 const Event& event)
103{
104 EventQueue::iterator i = m_events.insert(EventInfo(after, period, event));
Alexander Afanasyevb67090a2014-04-29 22:31:01 -0700105 i->m_eventId = make_shared<EventIdImpl>(func_lib::cref(i));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800106
107 if (!m_isEventExecuting)
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800108 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800109 if (m_scheduledEvent == m_events.end() ||
110 *i < *m_scheduledEvent)
111 {
112 m_deadlineTimer.expires_from_now(after);
113 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
114 m_scheduledEvent = i;
115 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800116 }
117
118 return i->m_eventId;
119}
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700120
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800121void
122Scheduler::cancelEvent(const EventId& eventId)
123{
Yingdi Yuab136552014-02-03 14:31:02 -0800124 if (!static_cast<bool>(eventId) || !eventId->isValid())
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800125 return; // event already fired or cancelled
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700126
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800127 if (static_cast<EventQueue::iterator>(*eventId) != m_scheduledEvent) {
128 m_events.erase(*eventId);
129 eventId->invalidate();
130 return;
131 }
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700132
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800133 m_deadlineTimer.cancel();
134 m_events.erase(static_cast<EventQueue::iterator>(*eventId));
135 eventId->invalidate();
136
Yingdi Yuf2a82092014-02-03 16:49:15 -0800137 if (!m_isEventExecuting)
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800138 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800139 if (!m_events.empty())
140 {
141 m_deadlineTimer.expires_from_now(m_events.begin()->expiresFromNow());
142 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
143 m_scheduledEvent = m_events.begin();
144 }
145 else
146 {
147 m_scheduledEvent = m_events.end();
148 }
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800149 }
150}
151
152void
153Scheduler::onEvent(const boost::system::error_code& error)
154{
155 if (error) // e.g., cancelled
156 {
157 return;
158 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800159
160 m_isEventExecuting = true;
161
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800162 // process all expired events
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700163 time::steady_clock::TimePoint now = time::steady_clock::now();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800164 while(!m_events.empty() && m_events.begin()->m_scheduledTime <= now)
165 {
166 EventQueue::iterator head = m_events.begin();
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -0700167
Yingdi Yuf2a82092014-02-03 16:49:15 -0800168 Event event = head->m_event;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700169 if (head->m_period < time::nanoseconds::zero())
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800170 {
Yingdi Yuf2a82092014-02-03 16:49:15 -0800171 head->m_eventId->invalidate();
172 m_events.erase(head);
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800173 }
174 else
175 {
176 // "reschedule" and update EventId data of the event
177 EventInfo event(now + head->m_period, *head);
178 EventQueue::iterator i = m_events.insert(event);
179 i->m_eventId->reset(i);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800180 m_events.erase(head);
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800181 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800182
183 event();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800184 }
185
186 if (!m_events.empty())
187 {
188 m_deadlineTimer.expires_from_now(m_events.begin()->m_scheduledTime - now);
189 m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800190 m_scheduledEvent = m_events.begin();
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800191 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800192 else
193 {
194 m_scheduledEvent = m_events.end();
195 }
196
197 m_isEventExecuting = false;
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800198}
199
200
201} // namespace ndn