Fix bug and tidy up DeadlineTimer

This commit is contained in:
Vinnie Falco
2013-09-04 14:43:57 -07:00
parent cca092f5d1
commit 8e75064fe3

View File

@@ -46,24 +46,24 @@ public:
// Okay to call on an active timer. // Okay to call on an active timer.
// However, an extra notification may still happen due to concurrency. // However, an extra notification may still happen due to concurrency.
// //
void activate (DeadlineTimer* timer, double secondsRecurring, Time const& when) void activate (DeadlineTimer& timer, double secondsRecurring, Time const& when)
{ {
bassert (secondsRecurring >= 0); bassert (secondsRecurring >= 0);
LockType::ScopedLockType lock (m_mutex); LockType::ScopedLockType lock (m_mutex);
if (timer->m_isActive) if (timer.m_isActive)
{ {
m_items.erase (m_items.iterator_to (*timer)); m_items.erase (m_items.iterator_to (timer));
timer->m_isActive = false; timer.m_isActive = false;
} }
timer->m_secondsRecurring = secondsRecurring; timer.m_secondsRecurring = secondsRecurring;
timer->m_notificationTime = when; timer.m_notificationTime = when;
insertSorted (*timer); insertSorted (timer);
timer->m_isActive = true; timer.m_isActive = true;
m_thread.interrupt (); m_thread.interrupt ();
} }
@@ -71,25 +71,26 @@ public:
// Okay to call this on an inactive timer. // Okay to call this on an inactive timer.
// This can happen naturally based on concurrency. // This can happen naturally based on concurrency.
// //
void deactivate (DeadlineTimer* timer) void deactivate (DeadlineTimer& timer)
{ {
LockType::ScopedLockType lock (m_mutex); LockType::ScopedLockType lock (m_mutex);
if (timer->m_isActive) if (timer.m_isActive)
{ {
m_items.erase (m_items.iterator_to (*timer)); m_items.erase (m_items.iterator_to (timer));
timer->m_isActive = false; timer.m_isActive = false;
}
m_thread.interrupt (); m_thread.interrupt ();
} }
}
void threadRun () void threadRun ()
{ {
while (! m_shouldStop) while (! m_shouldStop)
{ {
Time const currentTime = Time::getCurrentTime (); Time const currentTime = Time::getCurrentTime ();
double seconds = 0; double seconds = 0;
{ {
@@ -97,38 +98,39 @@ public:
// Notify everyone whose timer has expired // Notify everyone whose timer has expired
// //
if (! m_items.empty ()) while (! m_items.empty ())
{
for (;;)
{ {
Items::iterator const iter = m_items.begin (); Items::iterator const iter = m_items.begin ();
DeadlineTimer& timer (*iter);
// Has this timer expired? // Has this timer expired?
if (iter->m_notificationTime <= currentTime) if (timer.m_notificationTime <= currentTime)
{ {
// Yes, so call the listener. // Expired, remove it from the list.
//
// Note that this happens while the lock is held.
//
iter->m_listener->onDeadlineTimer (*iter);
// Remove it from the list.
m_items.erase (iter); m_items.erase (iter);
// Call the listener
//
// NOTE
// The lock is held.
// The listener MUST NOT block for long.
//
timer.m_listener->onDeadlineTimer (timer);
// Is the timer recurring? // Is the timer recurring?
if (iter->m_secondsRecurring > 0) if (timer.m_secondsRecurring > 0)
{ {
// Yes so set the timer again. // Yes so set the timer again.
iter->m_notificationTime = timer.m_notificationTime =
currentTime + RelativeTime (iter->m_secondsRecurring); currentTime + RelativeTime (iter->m_secondsRecurring);
// Keep it active. // Keep it active.
insertSorted (*iter); insertSorted (timer);
} }
else else
{ {
// Not a recurring timer, deactivate it. // Not a recurring timer, deactivate it.
iter->m_isActive = false; timer.m_isActive = false;
} }
} }
else else
@@ -136,7 +138,6 @@ public:
break; break;
} }
} }
}
// Figure out how long we need to wait. // Figure out how long we need to wait.
// This has to be done while holding the lock. // This has to be done while holding the lock.
@@ -175,7 +176,7 @@ public:
} }
// Caller is responsible for locking // Caller is responsible for locking
void insertSorted (DeadlineTimer& item) void insertSorted (DeadlineTimer& timer)
{ {
if (! m_items.empty ()) if (! m_items.empty ())
{ {
@@ -183,9 +184,9 @@ public:
for (;;) for (;;)
{ {
if (before->m_notificationTime >= item.m_notificationTime) if (before->m_notificationTime >= timer.m_notificationTime)
{ {
m_items.insert (before, item); m_items.insert (before, timer);
break; break;
} }
@@ -193,14 +194,14 @@ public:
if (before == m_items.end ()) if (before == m_items.end ())
{ {
m_items.push_back (item); m_items.push_back (timer);
break; break;
} }
} }
} }
else else
{ {
m_items.push_back (item); m_items.push_back (timer);
} }
} }
@@ -227,7 +228,7 @@ DeadlineTimer::DeadlineTimer (Listener* listener)
DeadlineTimer::~DeadlineTimer () DeadlineTimer::~DeadlineTimer ()
{ {
m_manager->deactivate (this); m_manager->deactivate (*this);
} }
void DeadlineTimer::setExpiration (double secondsUntilDeadline) void DeadlineTimer::setExpiration (double secondsUntilDeadline)
@@ -236,7 +237,7 @@ void DeadlineTimer::setExpiration (double secondsUntilDeadline)
Time const when = Time::getCurrentTime () + RelativeTime (secondsUntilDeadline); Time const when = Time::getCurrentTime () + RelativeTime (secondsUntilDeadline);
m_manager->activate (this, 0, when); m_manager->activate (*this, 0, when);
} }
void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline) void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline)
@@ -245,15 +246,15 @@ void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline)
Time const when = Time::getCurrentTime () + RelativeTime (secondsUntilDeadline); Time const when = Time::getCurrentTime () + RelativeTime (secondsUntilDeadline);
m_manager->activate (this, secondsUntilDeadline, when); m_manager->activate (*this, secondsUntilDeadline, when);
} }
void DeadlineTimer::setExpirationTime (Time const& when) void DeadlineTimer::setExpirationTime (Time const& when)
{ {
m_manager->activate (this, 0, when); m_manager->activate (*this, 0, when);
} }
void DeadlineTimer::reset () void DeadlineTimer::reset ()
{ {
m_manager->deactivate (this); m_manager->deactivate (*this);
} }