core: global io_service and scheduler
Scheduler and time are imported from ndn-cpp-dev.
Forwarder is using the new scheduler API.
Face system is not transitioned yet.
refs #1290
Change-Id: I5679cb50bbf9890a105f663b038f13951403c2b6
diff --git a/daemon/core/global-io.cpp b/daemon/core/global-io.cpp
new file mode 100644
index 0000000..74f1dc5
--- /dev/null
+++ b/daemon/core/global-io.cpp
@@ -0,0 +1,35 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "global-io.hpp"
+
+namespace nfd {
+
+namespace scheduler {
+// defined in scheduler.cpp
+void
+resetGlobalScheduler();
+} // namespace scheduler
+
+static shared_ptr<boost::asio::io_service> g_ioService;
+
+boost::asio::io_service&
+getGlobalIoService()
+{
+ if (!static_cast<bool>(g_ioService)) {
+ g_ioService = make_shared<boost::asio::io_service>();
+ }
+ return *g_ioService;
+}
+
+void
+resetGlobalIoService()
+{
+ scheduler::resetGlobalScheduler();
+ g_ioService.reset();
+}
+
+} // namespace nfd
diff --git a/daemon/core/global-io.hpp b/daemon/core/global-io.hpp
new file mode 100644
index 0000000..7e961f1
--- /dev/null
+++ b/daemon/core/global-io.hpp
@@ -0,0 +1,30 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_CORE_GLOBAL_IO_HPP
+#define NFD_CORE_GLOBAL_IO_HPP
+
+#include "common.hpp"
+
+namespace nfd {
+
+/** \return the global io_service instance
+ */
+boost::asio::io_service&
+getGlobalIoService();
+
+#ifdef WITH_TESTS
+/** \brief delete the global io_service instance
+ *
+ * It will be recreated at the next invocation of getGlobalIoService.
+ */
+void
+resetGlobalIoService();
+#endif
+
+} // namespace nfd
+
+#endif // NFD_CORE_GLOBAL_IO_HPP
diff --git a/daemon/core/monotonic_deadline_timer.hpp b/daemon/core/monotonic_deadline_timer.hpp
deleted file mode 100644
index c158fe4..0000000
--- a/daemon/core/monotonic_deadline_timer.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (C) 2014 Named Data Networking Project
- * See COPYING for copyright and distribution information.
- */
-
-/**
- * This code is based on https://svn.boost.org/trac/boost/attachment/ticket/3504/MonotonicDeadlineTimer.h
- */
-
-#ifndef NFD_CORE_MONOTONIC_DEADLINE_TIMER_HPP
-#define NFD_CORE_MONOTONIC_DEADLINE_TIMER_HPP
-
-#include "time.hpp"
-
-namespace boost {
-namespace asio {
-
-template <>
-struct time_traits<nfd::time::monotonic_clock>
-{
- typedef nfd::time::Point time_type;
- typedef nfd::time::Duration duration_type;
-
- static time_type
- now()
- {
- return nfd::time::now();
- }
-
- static time_type
- add(const time_type& time, const duration_type& duration)
- {
- return time + duration;
- }
-
- static duration_type
- subtract(const time_type& timeLhs, const time_type& timeRhs)
- {
- return timeLhs - timeRhs;
- }
-
- static bool
- less_than(const time_type& timeLhs, const time_type& timeRhs)
- {
- return timeLhs < timeRhs;
- }
-
- static boost::posix_time::time_duration
- to_posix_duration(const duration_type& duration)
- {
- return boost::posix_time::microseconds(duration/1000);
- }
-};
-
-typedef basic_deadline_timer<nfd::time::monotonic_clock> monotonic_deadline_timer;
-
-} // namespace asio
-} // namespace boost
-
-#endif // NFD_CORE_MONOTONIC_DEADLINE_TIMER_HPP
diff --git a/daemon/core/scheduler.cpp b/daemon/core/scheduler.cpp
index a1759ca..439b914 100644
--- a/daemon/core/scheduler.cpp
+++ b/daemon/core/scheduler.cpp
@@ -7,204 +7,24 @@
#include "scheduler.hpp"
namespace nfd {
+namespace scheduler {
-struct EventIdImpl
+static shared_ptr<Scheduler> g_scheduler;
+
+Scheduler&
+getGlobalScheduler()
{
- EventIdImpl(const Scheduler::EventQueue::iterator& event)
- : m_event(event)
- , m_isValid(true)
- {
+ if (!static_cast<bool>(g_scheduler)) {
+ g_scheduler = make_shared<Scheduler>(boost::ref(getGlobalIoService()));
}
-
- void
- invalidate()
- {
- m_isValid = false;
- }
-
- bool
- isValid() const
- {
- return m_isValid;
- }
-
- operator const Scheduler::EventQueue::iterator&() const
- {
- return m_event;
- }
-
- void
- reset(const Scheduler::EventQueue::iterator& newIterator)
- {
- m_event = newIterator;
- m_isValid = true;
- }
-
-private:
- Scheduler::EventQueue::iterator m_event;
- bool m_isValid;
-};
-
-Scheduler::EventInfo::EventInfo(const time::Duration& after,
- const time::Duration& period,
- const Event& event)
- : m_scheduledTime(time::now() + after)
- , m_period(period)
- , m_event(event)
-{
-}
-
-Scheduler::EventInfo::EventInfo(const time::Point& when, const EventInfo& previousEvent)
- : m_scheduledTime(when)
- , m_period(previousEvent.m_period)
- , m_event(previousEvent.m_event)
- , m_eventId(previousEvent.m_eventId)
-{
-}
-
-time::Duration
-Scheduler::EventInfo::expiresFromNow() const
-{
- time::Point now = time::now();
- if (now > m_scheduledTime)
- return time::seconds(0); // event should be scheduled ASAP
- else
- return m_scheduledTime - now;
-}
-
-
-Scheduler::Scheduler(boost::asio::io_service& ioService)
- : m_ioService(ioService)
- , m_scheduledEvent(m_events.end())
- , m_deadlineTimer(ioService)
- , m_isEventExecuting(false)
-{
-}
-
-EventId
-Scheduler::scheduleEvent(const time::Duration& after,
- const Event& event)
-{
- return schedulePeriodicEvent(after, time::nanoseconds(-1), event);
-}
-
-EventId
-Scheduler::schedulePeriodicEvent(const time::Duration& after,
- const time::Duration& period,
- const Event& event)
-{
- EventQueue::iterator i = m_events.insert(EventInfo(after, period, event));
- i->m_eventId = make_shared<EventIdImpl>(boost::cref(i));
-
- if (!m_isEventExecuting)
- {
- if (m_scheduledEvent == m_events.end() ||
- *i < *m_scheduledEvent)
- {
- m_deadlineTimer.expires_from_now(after);
- m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
- m_scheduledEvent = i;
- }
- }
-
- return i->m_eventId;
-}
-
-void
-Scheduler::cancelEvent(const EventId& eventId)
-{
- if (!static_cast<bool>(eventId) || !eventId->isValid())
- return; // event empty, already fired, or cancelled
-
- if (static_cast<EventQueue::iterator>(*eventId) != m_scheduledEvent) {
- m_events.erase(*eventId);
- eventId->invalidate();
- return;
- }
-
- m_deadlineTimer.cancel();
- m_events.erase(static_cast<EventQueue::iterator>(*eventId));
- eventId->invalidate();
-
- if (!m_isEventExecuting)
- {
- if (!m_events.empty())
- {
- m_deadlineTimer.expires_from_now(m_events.begin()->expiresFromNow());
- m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
- m_scheduledEvent = m_events.begin();
- }
- else
- {
- m_deadlineTimer.cancel();
- m_scheduledEvent = m_events.end();
- }
- }
+ return *g_scheduler;
}
void
-Scheduler::onEvent(const boost::system::error_code& error)
+resetGlobalScheduler()
{
- if (error) // e.g., cancelled
- {
- return;
- }
-
- m_isEventExecuting = true;
-
- // process all expired events
- time::Point now = time::now();
- while(!m_events.empty() && m_events.begin()->m_scheduledTime <= now)
- {
- EventQueue::iterator head = m_events.begin();
-
- Event event = head->m_event;
- if (head->m_period < 0)
- {
- head->m_eventId->invalidate();
- m_events.erase(head);
- }
- else
- {
- // "reschedule" and update EventId data of the event
- EventInfo event(now + head->m_period, *head);
- EventQueue::iterator i = m_events.insert(event);
- i->m_eventId->reset(i);
- m_events.erase(head);
- }
-
- try
- {
- event();
- }
- catch(...)
- {
- m_isEventExecuting = false;
- for (EventQueue::iterator i = m_events.begin();
- i != m_events.end();
- ++i)
- {
- i->m_eventId->invalidate();
- }
- m_events.clear();
-
- throw;
- }
- }
-
- if (!m_events.empty())
- {
- m_deadlineTimer.expires_from_now(m_events.begin()->m_scheduledTime - now);
- m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
- m_scheduledEvent = m_events.begin();
- }
- else
- {
- m_scheduledEvent = m_events.end();
- }
-
- m_isEventExecuting = false;
+ g_scheduler.reset();
}
-
+} // namespace scheduler
} // namespace nfd
diff --git a/daemon/core/scheduler.hpp b/daemon/core/scheduler.hpp
index a8e60bb..6ba4f80 100644
--- a/daemon/core/scheduler.hpp
+++ b/daemon/core/scheduler.hpp
@@ -7,95 +7,46 @@
#ifndef NFD_CORE_SCHEDULER_HPP
#define NFD_CORE_SCHEDULER_HPP
-#include "common.hpp"
-#include "monotonic_deadline_timer.hpp"
+#include "global-io.hpp"
+#include "time.hpp"
+#include <ndn-cpp-dev/util/scheduler.hpp>
namespace nfd {
+namespace scheduler {
-struct EventIdImpl; ///< \brief Private storage of information about the event
-/**
- * \brief Opaque type (shared_ptr) representing ID of the scheduled event
- */
-typedef shared_ptr<EventIdImpl> EventId;
+using ndn::Scheduler;
-/**
- * \brief Generic scheduler
+/** \class EventId
+ * \brief Opaque type (shared_ptr) representing ID of a scheduled event
*/
-class Scheduler
+using ndn::EventId;
+
+} // namespace scheduler
+
+// TODO delete this after transition
+using scheduler::Scheduler;
+
+using scheduler::EventId;
+
+namespace scheduler {
+
+// TODO delete this after transition
+Scheduler&
+getGlobalScheduler();
+
+inline EventId
+schedule(const time::Duration& after, const Scheduler::Event& event)
{
-public:
- typedef function<void()> Event;
+ return getGlobalScheduler().scheduleEvent(after, event);
+}
- Scheduler(boost::asio::io_service& ioService);
+inline void
+cancel(const EventId& eventId)
+{
+ getGlobalScheduler().cancelEvent(eventId);
+}
- /**
- * \brief Schedule one time event after the specified delay
- * \returns EventId that can be used to cancel the scheduled event
- */
- EventId
- scheduleEvent(const time::Duration& after, const Event& event);
-
- /**
- * \brief Schedule periodic event that should be fired every specified period.
- * First event will be fired after the specified delay.
- * \returns EventId that can be used to cancel the scheduled event
- */
- EventId
- schedulePeriodicEvent(const time::Duration& after,
- const time::Duration& period,
- const Event& event);
-
- /**
- * \brief Cancel scheduled event
- */
- void
- cancelEvent(const EventId& eventId);
-
-private:
- void
- onEvent(const boost::system::error_code& code);
-
-private:
- boost::asio::io_service& m_ioService;
-
- struct EventInfo
- {
- EventInfo(const time::Duration& after,
- const time::Duration& period,
- const Event& event);
- EventInfo(const time::Point& when, const EventInfo& previousEvent);
-
- 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::Duration
- expiresFromNow() const;
-
- time::Point m_scheduledTime;
- time::Duration m_period;
- Event m_event;
- mutable EventId m_eventId;
- };
-
- typedef std::multiset<EventInfo> EventQueue;
- friend struct EventIdImpl;
-
- EventQueue m_events;
- EventQueue::iterator m_scheduledEvent;
- boost::asio::monotonic_deadline_timer m_deadlineTimer;
-
- bool m_isEventExecuting;
-};
-
+} // namespace scheduler
} // namespace nfd
#endif // NFD_CORE_SCHEDULER_HPP
diff --git a/daemon/core/time.cpp b/daemon/core/time.cpp
deleted file mode 100644
index c216df4..0000000
--- a/daemon/core/time.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (C) 2014 Named Data Networking Project
- * See COPYING for copyright and distribution information.
- */
-
-#include "time.hpp"
-#include <time.h>
-#include <stdexcept>
-#include <sys/time.h>
-
-namespace nfd {
-namespace time {
-
-Point
-now()
-{
-#ifdef HAVE_RT
-
- struct timespec t;
- int res = clock_gettime(CLOCK_MONOTONIC, &t);
-
- if (res == -1) {
- throw std::runtime_error("clock_gettime");
- }
-
- return Point(time::seconds(t.tv_sec) + time::nanoseconds(t.tv_nsec));
-
-#else
- // fallback to wall clock time
-
- struct timeval tv;
- int res = gettimeofday(&tv, 0);
-
- if (res == -1) {
- throw std::runtime_error("gettimeofday");
- }
-
- return Point(time::seconds(tv.tv_sec) + time::microseconds(tv.tv_usec));
-
-#endif
-}
-
-} // namespace time
-} // namespace nfd
diff --git a/daemon/core/time.hpp b/daemon/core/time.hpp
index 5efd082..2c9498f 100644
--- a/daemon/core/time.hpp
+++ b/daemon/core/time.hpp
@@ -8,152 +8,19 @@
#define NFD_CORE_TIME_H
#include "common.hpp"
+#include <ndn-cpp-dev/util/time.hpp>
namespace nfd {
namespace time {
-class monotonic_clock;
-
-/** \class Duration
- * \brief represents a time interval
- * Time unit is nanosecond.
- */
-class Duration
-{
-public:
- Duration()
- : m_value(0)
- {
- }
-
- explicit
- Duration(int64_t value)
- : m_value(value)
- {
- }
-
- operator int64_t&()
- {
- return m_value;
- }
-
- operator const int64_t&() const
- {
- return m_value;
- }
-
- Duration
- operator+(const Duration& other) const
- {
- return Duration(this->m_value + other.m_value);
- }
-
- Duration
- operator-(const Duration& other) const
- {
- return Duration(this->m_value - other.m_value);
- }
-
-private:
- int64_t m_value;
-};
-
-/** \class Point
- * \brief represents a point in time
- * This uses monotonic clock.
- */
-class Point
-{
-public:
- Point()
- : m_value(0)
- {
- }
-
- explicit
- Point(int64_t value)
- : m_value(value)
- {
- }
-
- operator int64_t&()
- {
- return m_value;
- }
-
- operator const int64_t&() const
- {
- return m_value;
- }
-
- Point
- operator+(const Duration& other) const
- {
- return Point(this->m_value + static_cast<int64_t>(other));
- }
-
- Duration
- operator-(const Point& other) const
- {
- return Duration(this->m_value - other.m_value);
- }
-
- Point
- operator-(const Duration& other) const
- {
- return Point(this->m_value - static_cast<int64_t>(other));
- }
-
-private:
- int64_t m_value;
-};
-
-/**
- * \brief Get current time
- * \return{ the current time in monotonic clock }
- */
-Point
-now();
-
-/**
- * \brief Get time::Duration for the specified number of seconds
- */
-template<class T>
-inline Duration
-seconds(T value)
-{
- return Duration(value * static_cast<int64_t>(1000000000));
-}
-
-/**
- * \brief Get time::Duration for the specified number of milliseconds
- */
-template<class T>
-inline Duration
-milliseconds(T value)
-{
- return Duration(value * static_cast<int64_t>(1000000));
-}
-
-/**
- * \brief Get time::Duration for the specified number of microseconds
- */
-template<class T>
-inline Duration
-microseconds(T value)
-{
- return Duration(value * static_cast<int64_t>(1000));
-}
-
-/**
- * \brief Get time::Duration for the specified number of nanoseconds
- */
-inline Duration
-nanoseconds(int64_t value)
-{
- return Duration(value);
-}
-
+using ndn::time::Duration;
+using ndn::time::Point;
+using ndn::time::monotonic_clock;
+using ndn::time::now;
+using ndn::time::seconds;
+using ndn::time::milliseconds;
+using ndn::time::microseconds;
+using ndn::time::nanoseconds;
} // namespace time
} // namespace nfd