Keep timers with active waits referenced.

Avoids calling the wait callback with reference count zero. In case of a non-pending timer, the wait will be canceled if the wait reference is the last one to avoid keeping starved timers.
This commit is contained in:
Sönke Ludwig 2018-10-27 15:45:55 +02:00
parent 9b75a3b7d9
commit b33f710420

View file

@ -79,7 +79,10 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
foreach (tm; processed_timers) { foreach (tm; processed_timers) {
auto cb = tm.callback; auto cb = tm.callback;
tm.callback = null; tm.callback = null;
if (cb) cb(tm.id, true); if (cb) {
cb(tm.id, true);
releaseRef(tm.id);
}
} }
return processed_timers.length > 0; return processed_timers.length > 0;
@ -119,7 +122,10 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
if (!tm.pending) return; if (!tm.pending) return;
TimerCallback2 cb; TimerCallback2 cb;
swap(cb, tm.callback); swap(cb, tm.callback);
if (cb) cb(timer, false); if (cb) {
cb(timer, false);
releaseRef(timer);
}
tm.pending = false; tm.pending = false;
m_timerQueue.remove(tm); m_timerQueue.remove(tm);
} }
@ -138,6 +144,7 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
{ {
assert(!m_timers[timer].callback, "Calling wait() on a timer that is already waiting."); assert(!m_timers[timer].callback, "Calling wait() on a timer that is already waiting.");
m_timers[timer].callback = callback; m_timers[timer].callback = callback;
addRef(timer);
} }
alias wait = EventDriverTimers.wait; alias wait = EventDriverTimers.wait;
@ -146,6 +153,7 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
auto pt = m_timers[timer]; auto pt = m_timers[timer];
assert(pt.callback); assert(pt.callback);
pt.callback = null; pt.callback = null;
releaseRef(timer);
} }
final override void addRef(TimerID descriptor) final override void addRef(TimerID descriptor)
@ -164,7 +172,20 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
if (descriptor !in m_timers) return true; if (descriptor !in m_timers) return true;
auto tm = m_timers[descriptor]; auto tm = m_timers[descriptor];
if (!--tm.refCount) { tm.refCount--;
// cancel starved timer waits
if (tm.callback && tm.refCount == 1 && !tm.pending) {
debug addRef(descriptor);
cancelWait(tm.id);
debug {
assert(tm.refCount == 1);
releaseRef(descriptor);
}
return false;
}
if (!tm.refCount) {
if (tm.pending) stop(tm.id); if (tm.pending) stop(tm.id);
m_timers.remove(descriptor); m_timers.remove(descriptor);
() @trusted { () @trusted {