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;
 }