util: Fix rescheduling and add test case.

Change-Id: Ic04a590a116083391b441338eed9a121e14852dd
diff --git a/src/util/scheduler.cpp b/src/util/scheduler.cpp
index 13a6c3a..c13e070 100644
--- a/src/util/scheduler.cpp
+++ b/src/util/scheduler.cpp
@@ -77,6 +77,7 @@
   : m_ioService(ioService)
   , m_scheduledEvent(m_events.end())
   , m_deadlineTimer(ioService)
+  , m_isEventExecuting(false)
 {
 }
 
@@ -94,13 +95,16 @@
 {
   EventQueue::iterator i = m_events.insert(EventInfo(after, period, event));
   i->m_eventId = make_shared<EventIdImpl>(boost::cref(i));
-  
-  if (m_scheduledEvent == m_events.end() ||
-      *i < *m_scheduledEvent)
+
+  if (!m_isEventExecuting)
     {
-      m_deadlineTimer.expires_from_now(after);
-      m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
-      m_scheduledEvent = i;
+      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;
@@ -122,16 +126,18 @@
   m_events.erase(static_cast<EventQueue::iterator>(*eventId));
   eventId->invalidate();
 
-  if (!m_events.empty())
+  if (!m_isEventExecuting)
     {
-      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();
+      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_scheduledEvent = m_events.end();
+        }
     }
 }
 
@@ -142,40 +148,45 @@
     {
       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();
       
-      head->m_event();
+      Event event = head->m_event;
       if (head->m_period < 0)
         {
-          if(head->m_eventId->isValid())
-            {
-              head->m_eventId->invalidate();
-              m_events.erase(head);
-            }
+          head->m_eventId->invalidate();
+          m_events.erase(head);
         }
       else
         {
-          bool validity = head->m_eventId->isValid();
-
           // "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);
-          if(validity)
-            m_events.erase(head);
+          m_events.erase(head);
         }
+
+      event();
     }
 
   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;
 }
 
 
diff --git a/src/util/scheduler.hpp b/src/util/scheduler.hpp
index b1fb596..18c3004 100644
--- a/src/util/scheduler.hpp
+++ b/src/util/scheduler.hpp
@@ -92,6 +92,8 @@
   EventQueue m_events;
   EventQueue::iterator m_scheduledEvent;
   boost::asio::monotonic_deadline_timer m_deadlineTimer;
+
+  bool m_isEventExecuting;
 };
 
 } // namespace ndn
diff --git a/src/util/time.hpp b/src/util/time.hpp
index d175964..9af95fc 100644
--- a/src/util/time.hpp
+++ b/src/util/time.hpp
@@ -160,6 +160,13 @@
   int64_t m_value;
 };
 
+inline std::ostream&
+operator<<(std::ostream &os, const Duration& duration)
+{
+  os << static_cast<int64_t>(duration) / 1000000000.0 << " s";
+  return os;
+}
+
 /**
  * \brief Get current time
  * \return{ the current time in monotonic clock }