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
diff --git a/daemon/face/tcp-channel.hpp b/daemon/face/tcp-channel.hpp
index db6521f..354c849 100644
--- a/daemon/face/tcp-channel.hpp
+++ b/daemon/face/tcp-channel.hpp
@@ -8,7 +8,8 @@
 #define NFD_FACE_TCP_CHANNEL_HPP
 
 #include "common.hpp"
-#include "core/monotonic_deadline_timer.hpp"
+#include "core/time.hpp"
+#include <ndn-cpp-dev/util/monotonic_deadline_timer.hpp>
 #include "tcp-face.hpp"
 
 namespace nfd {
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 8f6f015..4cc93d0 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -14,10 +14,8 @@
 
 const Name Forwarder::s_localhostName("ndn:/localhost");
 
-Forwarder::Forwarder(boost::asio::io_service& ioService)
-  : m_scheduler(ioService)
-  , m_lastFaceId(0)
-  , m_measurements(ioService)
+Forwarder::Forwarder()
+  : m_lastFaceId(0)
 {
   m_strategy = make_shared<fw::BestRouteStrategy>(boost::ref(*this));
 }
@@ -43,12 +41,12 @@
   m_faces.erase(faceId);
   face->setId(INVALID_FACEID);
   NFD_LOG_INFO("removeFace id=" << faceId);
-  
+
   // XXX This clears all subscriptions, because EventEmitter
   //     does not support only removing Forwarder's subscription
   face->onReceiveInterest.clear();
   face->onReceiveData    .clear();
-  
+
   m_fib.removeNextHopFromAllEntries(face);
 }
 
@@ -77,7 +75,7 @@
   // receive Interest
   NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() << " interest=" << interest.getName());
   const_cast<Interest&>(interest).setIncomingFaceId(inFace.getId());
-  
+
   // /localhost scope control
   bool violatesLocalhost = !inFace.isLocal() &&
                            s_localhostName.isPrefixOf(interest.getName());
@@ -86,12 +84,12 @@
       << " interest=" << interest.getName() << " violates /localhost");
     return;
   }
-  
+
   // PIT insert
   std::pair<shared_ptr<pit::Entry>, bool>
     pitInsertResult = m_pit.insert(interest);
   shared_ptr<pit::Entry> pitEntry = pitInsertResult.first;
-  
+
   // detect loop and record Nonce
   bool isLoop = ! pitEntry->addNonce(interest.getNonce());
   if (isLoop) {
@@ -99,13 +97,13 @@
     this->onInterestLoop(inFace, interest, pitEntry);
     return;
   }
-  
+
   // cancel unsatisfy & straggler timer
   this->cancelUnsatisfyAndStragglerTimer(pitEntry);
-  
+
   const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
   bool isPending = inRecords.begin() == inRecords.end();
-  
+
   if (!isPending) {
     // CS lookup
     const Data* csMatch = m_cs.find(interest);
@@ -117,23 +115,23 @@
       return;
     }
   }
-  
+
   // insert InRecord
   pit::InRecordCollection::iterator inRecordIt =
     pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
-  
+
   // app chosen nexthops
   bool isAppChosenNexthops = false; // TODO get from local control header
   if (isAppChosenNexthops) {
     // TODO foreach chosen nexthop: goto outgoing Interest pipeline
     return;
   }
-  
+
   // FIB lookup
   shared_ptr<fib::Entry> fibEntry
     = m_fib.findLongestPrefixMatch(interest.getName());
   // TODO use Fib::findParent(pitEntry)
-  
+
   // dispatch to strategy
   this->dispatchToStrategy(inFace, interest, fibEntry, pitEntry);
 }
@@ -155,14 +153,14 @@
   // pick Interest
   const Interest& interest = pitEntry->getInterest();
   // TODO pick the last incoming Interest
-  
+
   // insert OutRecord
   pit::OutRecordCollection::iterator outRecordIt =
     pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), interest);
-  
+
   // set PIT unsatisfy timer
   this->setUnsatisfyTimer(pitEntry);
-  
+
   // send Interest
   outFace.sendInterest(interest);
 }
@@ -183,7 +181,7 @@
 
   // invoke PIT unsatisfied callback
   // TODO
-  
+
   // PIT delete
   m_pit.remove(pitEntry);
 }
@@ -194,7 +192,7 @@
   // receive Data
   NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() << " data=" << data.getName());
   const_cast<Data&>(data).setIncomingFaceId(inFace.getId());
-  
+
   // /localhost scope control
   bool violatesLocalhost = !inFace.isLocal() &&
                            s_localhostName.isPrefixOf(data.getName());
@@ -203,7 +201,7 @@
       << " interest=" << data.getName() << " violates /localhost");
     return;
   }
-  
+
   // PIT match
   shared_ptr<pit::DataMatchResult> pitMatches = m_pit.findAllDataMatches(data);
   if (pitMatches->begin() == pitMatches->end()) {
@@ -211,20 +209,20 @@
     this->onDataUnsolicited(inFace, data);
     return;
   }
-  
+
   // CS insert
   m_cs.insert(data);
-  
+
   std::set<shared_ptr<Face> > pendingDownstreams;
   // foreach PitEntry
   for (pit::DataMatchResult::iterator it = pitMatches->begin();
        it != pitMatches->end(); ++it) {
     shared_ptr<pit::Entry> pitEntry = *it;
     NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
-    
+
     // cancel unsatisfy & straggler timer
     this->cancelUnsatisfyAndStragglerTimer(pitEntry);
-    
+
     // remember pending downstreams
     const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
     for (pit::InRecordCollection::const_iterator it = inRecords.begin();
@@ -233,18 +231,18 @@
         pendingDownstreams.insert(it->getFace());
       }
     }
-    
+
     // mark PIT satisfied
     pitEntry->deleteInRecords();
     pitEntry->deleteOutRecord(inFace.shared_from_this());
-    
+
     // set PIT straggler timer
     this->setStragglerTimer(pitEntry);
-    
+
     // invoke PIT satisfy callback
     // TODO
   }
-  
+
   // foreach pending downstream
   for (std::set<shared_ptr<Face> >::iterator it = pendingDownstreams.begin();
       it != pendingDownstreams.end(); ++it) {
@@ -273,7 +271,7 @@
 
   // traffic manager
   // pass through
-  
+
   // send Data
   outFace.sendData(data);
 }
@@ -297,8 +295,8 @@
   if (lastExpiryFromNow <= time::seconds(0)) {
     // TODO all InRecords are already expired; will this happen?
   }
-  
-  pitEntry->m_unsatisfyTimer = m_scheduler.scheduleEvent(lastExpiryFromNow,
+
+  pitEntry->m_unsatisfyTimer = scheduler::schedule(lastExpiryFromNow,
     bind(&Forwarder::onInterestUnsatisfied, this, pitEntry));
 }
 
@@ -306,16 +304,16 @@
 Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry)
 {
   time::Duration stragglerTime = time::milliseconds(100);
-  
-  pitEntry->m_stragglerTimer = m_scheduler.scheduleEvent(stragglerTime,
+
+  pitEntry->m_stragglerTimer = scheduler::schedule(stragglerTime,
     bind(&Pit::remove, &m_pit, pitEntry));
 }
 
 void
 Forwarder::cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry)
 {
-  m_scheduler.cancelEvent(pitEntry->m_unsatisfyTimer);
-  m_scheduler.cancelEvent(pitEntry->m_stragglerTimer);
+  scheduler::cancel(pitEntry->m_unsatisfyTimer);
+  scheduler::cancel(pitEntry->m_stragglerTimer);
 }
 
 void
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index 6da99c7..51932d1 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -20,14 +20,13 @@
 
 /**
  * Forwarder is the main class of NFD.
- * 
+ *
  * It creates and owns a set of Face listeners
  */
 class Forwarder
 {
 public:
-  explicit
-  Forwarder(boost::asio::io_service& ioService);
+  Forwarder();
 
   void
   addFace(shared_ptr<Face> face);
@@ -40,17 +39,17 @@
 
   void
   onData(Face& face, const Data& data);
-  
+
 public:
   Fib&
   getFib();
-  
+
   Pit&
   getPit();
-  
+
   Cs&
   getCs();
-  
+
   Measurements&
   getMeasurements();
 
@@ -68,32 +67,32 @@
   VIRTUAL_WITH_TESTS void
   onInterestLoop(Face& inFace, const Interest& interest,
                  shared_ptr<pit::Entry> pitEntry);
-  
+
   /** \brief outgoing Interest pipeline
    */
   VIRTUAL_WITH_TESTS void
   onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace);
-  
+
   /** \brief Interest rebuff pipeline
    */
   VIRTUAL_WITH_TESTS void
   onInterestRebuff(shared_ptr<pit::Entry> pitEntry);
-  
+
   /** \brief Interest unsatisfied pipeline
    */
   VIRTUAL_WITH_TESTS void
   onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry);
-  
+
   /** \brief incoming Data pipeline
    */
   VIRTUAL_WITH_TESTS void
   onIncomingData(Face& inFace, const Data& data);
-  
+
   /** \brief Data unsolicited pipeline
    */
   VIRTUAL_WITH_TESTS void
   onDataUnsolicited(Face& inFace, const Data& data);
-  
+
   /** \brief outgoing Data pipeline
    */
   VIRTUAL_WITH_TESTS void
@@ -102,13 +101,13 @@
 PROTECTED_WITH_TESTS_ELSE_PRIVATE:
   VIRTUAL_WITH_TESTS void
   setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry);
-  
+
   VIRTUAL_WITH_TESTS void
   setStragglerTimer(shared_ptr<pit::Entry> pitEntry);
-  
+
   VIRTUAL_WITH_TESTS void
   cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry);
-  
+
   VIRTUAL_WITH_TESTS void
   dispatchToStrategy(const Face& inFace,
                      const Interest& interest,
@@ -116,20 +115,18 @@
                      shared_ptr<pit::Entry> pitEntry);
 
 private:
-  Scheduler m_scheduler;
-  
   FaceId m_lastFaceId;
   std::map<FaceId, shared_ptr<Face> > m_faces;
-  
+
   Fib          m_fib;
   Pit          m_pit;
   Cs           m_cs;
   Measurements m_measurements;
   /// the active strategy (only one strategy in mock)
   shared_ptr<fw::Strategy> m_strategy;
-  
+
   static const Name s_localhostName;
-  
+
   // allow Strategy (base class) to enter pipelines
   friend class fw::Strategy;
 };
diff --git a/daemon/main.cpp b/daemon/main.cpp
index 226fbe6..46b5bd3 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -27,7 +27,7 @@
       : m_endpoint(endpoint)
     {
     }
-    
+
     std::pair<std::string, std::string> m_endpoint;
     std::vector<Name> m_prefixes;
   };
@@ -38,7 +38,6 @@
   std::string m_unixListen;
 };
 
-static boost::asio::io_service g_ioService;
 static ProgramOptions g_options;
 static Forwarder* g_forwarder;
 static FibManager* g_fibManager;
@@ -83,7 +82,7 @@
   if (pos == std::string::npos) {
     throw std::invalid_argument("ip:port");
   }
-  
+
   return std::make_pair(s.substr(0, pos), s.substr(pos+1));
 }
 
@@ -94,7 +93,7 @@
   g_options.m_tcpListen = std::make_pair("0.0.0.0", "6363");
   g_options.m_unixListen = "/var/run/nfd.sock";
   g_options.m_tcpOutgoings.clear();
-  
+
   while (1) {
     int option_index = 0;
     static ::option long_options[] = {
@@ -107,7 +106,7 @@
     };
     int c = getopt_long_only(argc, argv, "", long_options, &option_index);
     if (c == -1) break;
-    
+
     switch (c) {
       case 0:
         switch (option_index) {
@@ -147,7 +146,7 @@
 {
   g_forwarder->addFace(newFace);
   newFace->onFail += bind(&onFaceFail, newFace, _1);
-  
+
   // add nexthop on prefixes
   if (prefixes != 0) {
     Fib& fib = g_forwarder->getFib();
@@ -170,17 +169,17 @@
 void
 initializeTcp()
 {
-  g_tcpFactory = new TcpChannelFactory(g_ioService);
+  g_tcpFactory = new TcpChannelFactory(getGlobalIoService());
   g_tcpChannel = g_tcpFactory->create(g_options.m_tcpListen.first,
                                       g_options.m_tcpListen.second);
   g_tcpChannel->listen(
     bind(&onFaceEstablish, _1, static_cast<std::vector<Name>*>(0)),
     &onFaceError);
-  
+
   for (std::vector<ProgramOptions::TcpOutgoing>::iterator it =
       g_options.m_tcpOutgoings.begin();
       it != g_options.m_tcpOutgoings.end(); ++it) {
-    g_tcpChannel->connect(it->m_endpoint.first, it->m_endpoint.second, 
+    g_tcpChannel->connect(it->m_endpoint.first, it->m_endpoint.second,
       bind(&onFaceEstablish, _1, &(it->m_prefixes)), &onFaceError);
   }
 }
@@ -189,7 +188,7 @@
 void
 initializeUnix()
 {
-  g_unixFactory = new UnixStreamChannelFactory(g_ioService);
+  g_unixFactory = new UnixStreamChannelFactory(getGlobalIoService());
   g_unixChannel = g_unixFactory->create(g_options.m_unixListen);
 
   g_unixChannel->listen(
@@ -224,8 +223,8 @@
     usage(argv[0]);
     return 0;
   }
-  
-  g_forwarder = new Forwarder(g_ioService);
+
+  g_forwarder = new Forwarder();
   initializeTcp();
 #ifdef HAVE_UNIX_SOCKETS
   initializeUnix();
@@ -233,14 +232,14 @@
   initializeMgmt();
 
   /// \todo Add signal processing to gracefully terminate the app
-  
+
   try {
-    g_ioService.run();
+    getGlobalIoService().run();
   } catch(std::exception& ex) {
     NFD_LOG_ERROR(ex.what());
     return 1;
   }
-  
+
   return 0;
 }
 
diff --git a/daemon/table/measurements.cpp b/daemon/table/measurements.cpp
index 705d3f1..ed01018 100644
--- a/daemon/table/measurements.cpp
+++ b/daemon/table/measurements.cpp
@@ -13,8 +13,7 @@
 
 const time::Duration Measurements::s_defaultLifetime = time::seconds(4);
 
-Measurements::Measurements(boost::asio::io_service& ioService)
-  : m_scheduler(ioService)
+Measurements::Measurements()
 {
 }
 
@@ -92,9 +91,9 @@
     return;
   }
 
-  m_scheduler.cancelEvent(entry->m_cleanup);
+  scheduler::cancel(entry->m_cleanup);
   entry->m_expiry = expiry;
-  entry->m_cleanup = m_scheduler.scheduleEvent(lifetime,
+  entry->m_cleanup = scheduler::schedule(lifetime,
                          bind(&Measurements::cleanup, this, it));
 }
 
diff --git a/daemon/table/measurements.hpp b/daemon/table/measurements.hpp
index 0fa24e0..4c6d946 100644
--- a/daemon/table/measurements.hpp
+++ b/daemon/table/measurements.hpp
@@ -20,8 +20,7 @@
 class Measurements : noncopyable
 {
 public:
-  explicit
-  Measurements(boost::asio::io_service& ioService);
+  Measurements();
 
   ~Measurements();
 
@@ -71,7 +70,6 @@
 private:
   std::map<Name, shared_ptr<measurements::Entry> > m_table;
 
-  Scheduler m_scheduler;
   static const time::Duration s_defaultLifetime;
 };