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-2020 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 
23 #include "ndn-cxx/util/impl/steady-timer.hpp"
24 #include "ndn-cxx/util/scope.hpp"
25 
26 namespace ndn {
27 namespace scheduler {
28 
31 class EventInfo : noncopyable
32 {
33 public:
34  EventInfo(time::nanoseconds after, EventCallback&& cb)
35  : callback(std::move(cb))
36  , expireTime(time::steady_clock::now() + after)
37  {
38  }
39 
40  NDN_CXX_NODISCARD time::nanoseconds
41  expiresFromNow() const
42  {
43  return std::max(expireTime - time::steady_clock::now(), 0_ns);
44  }
45 
46 public:
47  EventCallback callback;
48  Scheduler::EventQueue::const_iterator queueIt;
50  bool isExpired = false;
51 };
52 
53 EventId::EventId(Scheduler& sched, weak_ptr<EventInfo> info)
54  : CancelHandle([&sched, info] { sched.cancelImpl(info.lock()); })
55  , m_info(std::move(info))
56 {
57 }
58 
59 EventId::operator bool() const noexcept
60 {
61  auto sp = m_info.lock();
62  return sp != nullptr && !sp->isExpired;
63 }
64 
65 void
66 EventId::reset() noexcept
67 {
68  *this = {};
69 }
70 
71 std::ostream&
72 operator<<(std::ostream& os, const EventId& eventId)
73 {
74  return os << eventId.m_info.lock();
75 }
76 
77 bool
78 Scheduler::EventQueueCompare::operator()(const shared_ptr<EventInfo>& a,
79  const shared_ptr<EventInfo>& b) const noexcept
80 {
81  return a->expireTime < b->expireTime;
82 }
83 
84 Scheduler::Scheduler(boost::asio::io_service& ioService)
85  : m_timer(make_unique<util::detail::SteadyTimer>(ioService))
86 {
87 }
88 
89 Scheduler::~Scheduler() = default;
90 
91 EventId
92 Scheduler::schedule(time::nanoseconds after, EventCallback callback)
93 {
94  BOOST_ASSERT(callback != nullptr);
95 
96  auto i = m_queue.insert(std::make_shared<EventInfo>(after, std::move(callback)));
97  (*i)->queueIt = i;
98 
99  if (!m_isEventExecuting && i == m_queue.begin()) {
100  // the new event is the first one to expire
101  scheduleNext();
102  }
103 
104  return EventId(*this, *i);
105 }
106 
107 void
108 Scheduler::cancelImpl(const shared_ptr<EventInfo>& info)
109 {
110  if (info == nullptr || info->isExpired) {
111  return;
112  }
113 
114  if (info->queueIt == m_queue.begin()) {
115  m_timer->cancel();
116  }
117  m_queue.erase(info->queueIt);
118 
119  if (!m_isEventExecuting) {
120  scheduleNext();
121  }
122 }
123 
124 void
126 {
127  m_queue.clear();
128  m_timer->cancel();
129 }
130 
131 void
132 Scheduler::scheduleNext()
133 {
134  if (!m_queue.empty()) {
135  m_timer->expires_from_now((*m_queue.begin())->expiresFromNow());
136  m_timer->async_wait([this] (const auto& error) { this->executeEvent(error); });
137  }
138 }
139 
140 void
141 Scheduler::executeEvent(const boost::system::error_code& error)
142 {
143  if (error) { // e.g., cancelled
144  return;
145  }
146 
147  auto guard = make_scope_exit([this] {
148  m_isEventExecuting = false;
149  scheduleNext();
150  });
151  m_isEventExecuting = true;
152 
153  // process all expired events
154  auto now = time::steady_clock::now();
155  while (!m_queue.empty()) {
156  auto head = m_queue.begin();
157  shared_ptr<EventInfo> info = *head;
158  if (info->expireTime > now) {
159  break;
160  }
161 
162  m_queue.erase(head);
163  info->isExpired = true;
164  info->callback();
165  }
166 }
167 
168 } // namespace scheduler
169 } // namespace ndn
time_point TimePoint
Definition: time.hpp:225
Definition: data.cpp:26
void reset() noexcept
Clear this EventId without canceling.
Definition: scheduler.cpp:66
std::function< void()> EventCallback
Function to be invoked when a scheduled event expires.
Definition: scheduler.hpp:47
static time_point now() noexcept
Definition: time.cpp:80
EventId schedule(time::nanoseconds after, EventCallback callback)
Schedule a one-time event after the specified delay.
Definition: scheduler.cpp:92
A handle for a scheduled event.
Definition: scheduler.hpp:60
EventId() noexcept=default
Constructs an empty EventId.
std::ostream & operator<<(std::ostream &os, const EventId &eventId)
Definition: scheduler.cpp:72
#define NDN_CXX_NODISCARD
Definition: backports.hpp:68
Generic time-based scheduler.
Definition: scheduler.hpp:134
Scheduler(boost::asio::io_service &ioService)
Definition: scheduler.cpp:84
void cancelAllEvents()
Cancel all scheduled events.
Definition: scheduler.cpp:125