scheduler.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2018 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * 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.
20  */
21 
22 #include "scheduler.hpp"
23 #include "detail/steady-timer.hpp"
24 
25 #include <boost/scope_exit.hpp>
26 
27 namespace ndn {
28 namespace util {
29 namespace scheduler {
30 
31 class EventInfo : noncopyable
32 {
33 public:
34  EventInfo(time::nanoseconds after, const EventCallback& callback)
35  : expireTime(time::steady_clock::now() + after)
36  , isExpired(false)
37  , callback(callback)
38  {
39  }
40 
41  time::nanoseconds
42  expiresFromNow() const
43  {
44  return std::max(expireTime - time::steady_clock::now(), time::nanoseconds::zero());
45  }
46 
47 public:
49  bool isExpired;
50  EventCallback callback;
51  EventQueue::const_iterator queueIt;
52 };
53 
54 EventId::operator bool() const
55 {
56  return !m_info.expired() && !m_info.lock()->isExpired;
57 }
58 
59 bool
60 EventId::operator==(const EventId& other) const
61 {
62  return (!(*this) && !other) ||
63  !(m_info.owner_before(other.m_info) || other.m_info.owner_before(m_info));
64 }
65 
66 std::ostream&
67 operator<<(std::ostream& os, const EventId& eventId)
68 {
69  return os << eventId.m_info.lock();
70 }
71 
72 bool
73 EventQueueCompare::operator()(const shared_ptr<EventInfo>& a, const shared_ptr<EventInfo>& b) const
74 {
75  return a->expireTime < b->expireTime;
76 }
77 
78 Scheduler::Scheduler(boost::asio::io_service& ioService)
79  : m_timer(make_unique<detail::SteadyTimer>(ioService))
80  , m_isEventExecuting(false)
81 {
82 }
83 
84 Scheduler::~Scheduler() = default;
85 
86 EventId
87 Scheduler::scheduleEvent(time::nanoseconds after, const EventCallback& callback)
88 {
89  BOOST_ASSERT(callback != nullptr);
90 
91  EventQueue::iterator i = m_queue.insert(make_shared<EventInfo>(after, callback));
92  (*i)->queueIt = i;
93 
94  if (!m_isEventExecuting && i == m_queue.begin()) {
95  // the new event is the first one to expire
96  this->scheduleNext();
97  }
98 
99  return EventId(*i);
100 }
101 
102 void
104 {
105  shared_ptr<EventInfo> info = eventId.m_info.lock();
106  if (info == nullptr || info->isExpired) {
107  return; // event already expired or cancelled
108  }
109 
110  if (info->queueIt == m_queue.begin()) {
111  m_timer->cancel();
112  }
113  m_queue.erase(info->queueIt);
114 
115  if (!m_isEventExecuting) {
116  this->scheduleNext();
117  }
118 }
119 
120 void
122 {
123  m_queue.clear();
124  m_timer->cancel();
125 }
126 
127 void
128 Scheduler::scheduleNext()
129 {
130  if (!m_queue.empty()) {
131  m_timer->expires_from_now((*m_queue.begin())->expiresFromNow());
132  m_timer->async_wait(bind(&Scheduler::executeEvent, this, _1));
133  }
134 }
135 
136 void
137 Scheduler::executeEvent(const boost::system::error_code& error)
138 {
139  if (error) { // e.g., cancelled
140  return;
141  }
142 
143  m_isEventExecuting = true;
144 
145  BOOST_SCOPE_EXIT(this_) {
146  this_->m_isEventExecuting = false;
147  this_->scheduleNext();
148  } BOOST_SCOPE_EXIT_END
149 
150  // process all expired events
151  auto now = time::steady_clock::now();
152  while (!m_queue.empty()) {
153  auto head = m_queue.begin();
154  shared_ptr<EventInfo> info = *head;
155  if (info->expireTime > now) {
156  break;
157  }
158 
159  m_queue.erase(head);
160  info->isExpired = true;
161  info->callback();
162  }
163 }
164 
165 } // namespace scheduler
166 } // namespace util
167 } // namespace ndn
time_point TimePoint
Definition: time.hpp:226
Copyright (c) 2013-2017 Regents of the University of California.
Definition: common.hpp:66
bool operator()(const shared_ptr< EventInfo > &a, const shared_ptr< EventInfo > &b) const
Definition: scheduler.cpp:73
static time_point now() noexcept
Definition: time.cpp:80
unique_ptr< T > make_unique(Args &&...args)
Definition: backports.hpp:73
void cancelEvent(const EventId &eventId)
Cancel a scheduled event.
Definition: scheduler.cpp:103
EventId scheduleEvent(time::nanoseconds after, const EventCallback &callback)
Schedule a one-time event after the specified delay.
Definition: scheduler.cpp:87
void cancelAllEvents()
Cancel all scheduled events.
Definition: scheduler.cpp:121
std::function< void()> EventCallback
Function to be invoked when a scheduled event expires.
Definition: scheduler.hpp:43
Scheduler(boost::asio::io_service &ioService)
Definition: scheduler.cpp:78
bool operator==(const EventId &other) const
Definition: scheduler.cpp:60
Identifies a scheduled event.
Definition: scheduler.hpp:53
std::ostream & operator<<(std::ostream &os, const EventId &eventId)
Definition: scheduler.cpp:67