[ndnSIM] util: Redirecting the scheduler of ndn-cxx to the scheduler of NS3
Change-Id: I82fdd94582a731c2238c6645e9ace21a2cacf2de
Refs: #4509
diff --git a/src/util/scheduler.cpp b/src/util/scheduler.cpp
index 167b6e0..513348f 100644
--- a/src/util/scheduler.cpp
+++ b/src/util/scheduler.cpp
@@ -24,142 +24,82 @@
#include <boost/scope_exit.hpp>
+namespace ns3 {
+
+/// @cond include_hidden
+
+template<>
+struct EventMemberImplObjTraits<std::function<void()>> {
+ typedef std::function<void()> T;
+ static T&
+ GetReference(T& p)
+ {
+ return p;
+ }
+};
+
+/// @endcond
+
+} // namespace ns3
+
namespace ndn {
namespace util {
namespace scheduler {
-class EventInfo : noncopyable
-{
-public:
- EventInfo(time::nanoseconds after, const EventCallback& callback)
- : expireTime(time::steady_clock::now() + after)
- , isExpired(false)
- , callback(callback)
- {
- }
-
- time::nanoseconds
- expiresFromNow() const
- {
- return std::max(expireTime - time::steady_clock::now(), time::nanoseconds::zero());
- }
-
-public:
- time::steady_clock::TimePoint expireTime;
- bool isExpired;
- EventCallback callback;
- EventQueue::const_iterator queueIt;
-};
-
-EventId::operator bool() const
-{
- return !m_info.expired() && !m_info.lock()->isExpired;
-}
-
-bool
-EventId::operator==(const EventId& other) const
-{
- return (!(*this) && !other) ||
- !(m_info.owner_before(other.m_info) || other.m_info.owner_before(m_info));
-}
-
-std::ostream&
-operator<<(std::ostream& os, const EventId& eventId)
-{
- return os << eventId.m_info.lock();
-}
-
-bool
-EventQueueCompare::operator()(const shared_ptr<EventInfo>& a, const shared_ptr<EventInfo>& b) const
-{
- return a->expireTime < b->expireTime;
-}
-
Scheduler::Scheduler(boost::asio::io_service& ioService)
- : m_timer(make_unique<detail::SteadyTimer>(ioService))
- , m_isEventExecuting(false)
+ : m_scheduledEvent(m_events.end())
{
}
-Scheduler::~Scheduler() = default;
+Scheduler::~Scheduler()
+{
+ cancelAllEvents();
+}
EventId
-Scheduler::scheduleEvent(time::nanoseconds after, const EventCallback& callback)
+Scheduler::scheduleEvent(const time::nanoseconds& after, const Event& event)
{
- BOOST_ASSERT(callback != nullptr);
+ EventId eventId = std::make_shared<ns3::EventId>();
+ weak_ptr<ns3::EventId> eventWeak = eventId;
+ std::function<void()> eventWithCleanup = [this, event, eventWeak] () {
+ event();
+ shared_ptr<ns3::EventId> eventId = eventWeak.lock();
+ if (eventId != nullptr) {
+ this->m_events.erase(eventId); // remove the event from the set after it is executed
+ }
+ };
- EventQueue::iterator i = m_queue.insert(make_shared<EventInfo>(after, callback));
- (*i)->queueIt = i;
+ ns3::EventId id = ns3::Simulator::Schedule(ns3::NanoSeconds(after.count()),
+ &std::function<void()>::operator(), eventWithCleanup);
+ *eventId = std::move(id);
+ m_events.insert(eventId);
- if (!m_isEventExecuting && i == m_queue.begin()) {
- // the new event is the first one to expire
- this->scheduleNext();
- }
-
- return EventId(*i);
+ return eventId;
}
void
Scheduler::cancelEvent(const EventId& eventId)
{
- shared_ptr<EventInfo> info = eventId.m_info.lock();
- if (info == nullptr || info->isExpired) {
- return; // event already expired or cancelled
- }
-
- if (info->queueIt == m_queue.begin()) {
- m_timer->cancel();
- }
- m_queue.erase(info->queueIt);
-
- if (!m_isEventExecuting) {
- this->scheduleNext();
+ if (eventId != nullptr) {
+ ns3::Simulator::Remove(*eventId);
+ m_events.erase(eventId);
+ const_cast<EventId&>(eventId).reset();
}
}
void
Scheduler::cancelAllEvents()
{
- m_queue.clear();
- m_timer->cancel();
-}
-
-void
-Scheduler::scheduleNext()
-{
- if (!m_queue.empty()) {
- m_timer->expires_from_now((*m_queue.begin())->expiresFromNow());
- m_timer->async_wait(bind(&Scheduler::executeEvent, this, _1));
- }
-}
-
-void
-Scheduler::executeEvent(const boost::system::error_code& error)
-{
- if (error) { // e.g., cancelled
- return;
- }
-
- m_isEventExecuting = true;
-
- BOOST_SCOPE_EXIT(this_) {
- this_->m_isEventExecuting = false;
- this_->scheduleNext();
- } BOOST_SCOPE_EXIT_END
-
- // process all expired events
- auto now = time::steady_clock::now();
- while (!m_queue.empty()) {
- auto head = m_queue.begin();
- shared_ptr<EventInfo> info = *head;
- if (info->expireTime > now) {
- break;
+ for (auto i = m_events.begin(); i != m_events.end(); ) {
+ auto next = i;
+ ++next; // ns3::Simulator::Remove can call cancelEvent
+ if ((*i) != nullptr) {
+ ns3::Simulator::Remove((**i));
+ const_cast<EventId&>(*i).reset();
}
-
- m_queue.erase(head);
- info->isExpired = true;
- info->callback();
+ i = next;
}
+ m_events.clear();
}
} // namespace scheduler
diff --git a/src/util/scheduler.hpp b/src/util/scheduler.hpp
index 79fbf23..2d669b1 100644
--- a/src/util/scheduler.hpp
+++ b/src/util/scheduler.hpp
@@ -26,6 +26,12 @@
#include "../net/asio-fwd.hpp"
#include <boost/system/error_code.hpp>
+#include "../common.hpp"
+
+#include "ns3/simulator.h"
+
+#include <set>
+#include <boost/asio/io_service.hpp>
#include <set>
namespace ndn {
@@ -37,85 +43,12 @@
namespace scheduler {
-/**
- * \brief Function to be invoked when a scheduled event expires
+typedef function<void()> EventCallback;
+
+/** \class EventId
+ * \brief Opaque type (shared_ptr) representing ID of a scheduled event
*/
-using EventCallback = std::function<void()>;
-
-/**
- * \brief Stores internal information about a scheduled event
- */
-class EventInfo;
-
-/**
- * \brief Identifies a scheduled event
- */
-class EventId
-{
-public:
- /**
- * \brief Constructs an empty EventId
- * \note EventId is implicitly convertible from nullptr.
- */
- EventId(std::nullptr_t = nullptr)
- {
- }
-
- /**
- * \retval true The event is valid.
- * \retval false This EventId is empty, or the event is expired or cancelled.
- */
- explicit
- operator bool() const;
-
- /**
- * \return whether this and other refer to the same event, or are both empty/expired/cancelled
- */
- bool
- operator==(const EventId& other) const;
-
- bool
- operator!=(const EventId& other) const
- {
- return !this->operator==(other);
- }
-
- /**
- * \brief clear this EventId
- * \note This does not cancel the event.
- * \post !(*this)
- */
- void
- reset()
- {
- m_info.reset();
- }
-
-private:
- explicit
- EventId(const weak_ptr<EventInfo>& info)
- : m_info(info)
- {
- }
-
-private:
- weak_ptr<EventInfo> m_info;
-
- friend class Scheduler;
- friend std::ostream& operator<<(std::ostream& os, const EventId& eventId);
-};
-
-std::ostream&
-operator<<(std::ostream& os, const EventId& eventId);
-
-class EventQueueCompare
-{
-public:
- bool
- operator()(const shared_ptr<EventInfo>& a, const shared_ptr<EventInfo>& b) const;
-};
-
-using EventQueue = std::multiset<shared_ptr<EventInfo>, EventQueueCompare>;
+typedef std::shared_ptr<ns3::EventId> EventId;
/**
* \brief Generic scheduler
@@ -123,6 +56,11 @@
class Scheduler : noncopyable
{
public:
+ /**
+ * \deprecated use EventCallback
+ */
+ typedef EventCallback Event;
+
explicit
Scheduler(boost::asio::io_service& ioService);
@@ -133,7 +71,7 @@
* \return EventId that can be used to cancel the scheduled event
*/
EventId
- scheduleEvent(time::nanoseconds after, const EventCallback& callback);
+ scheduleEvent(const time::nanoseconds& after, const Event& event);
/**
* \brief Cancel a scheduled event
@@ -148,25 +86,36 @@
cancelAllEvents();
private:
- /**
- * \brief Schedule the next event on the deadline timer
- */
- void
- scheduleNext();
+ struct EventInfo
+ {
+ EventInfo(const time::nanoseconds& after, const Event& event);
- /**
- * \brief Execute expired events
- * \note If an event callback throws, the exception is propagated to the thread running the
- * io_service. In case there are other expired events, they will be processed in the next
- * invocation of this method.
- */
- void
- executeEvent(const boost::system::error_code& code);
+ EventInfo(const time::steady_clock::TimePoint& when, const EventInfo& previousEvent);
-private:
- unique_ptr<detail::SteadyTimer> m_timer;
- EventQueue m_queue;
- bool m_isEventExecuting;
+ bool
+ operator <=(const EventInfo& other) const
+ {
+ return this->m_scheduledTime <= other.m_scheduledTime;
+ }
+
+ bool
+ operator <(const EventInfo& other) const
+ {
+ return this->m_scheduledTime < other.m_scheduledTime;
+ }
+
+ time::nanoseconds
+ expiresFromNow() const;
+
+ time::steady_clock::TimePoint m_scheduledTime;
+ Event m_event;
+ mutable EventId m_eventId;
+ };
+
+ typedef std::multiset<EventId> EventQueue;
+
+ EventQueue m_events;
+ EventQueue::iterator m_scheduledEvent;
};
} // namespace scheduler