From b33f710420f19a81e648cb01b1422a3b86ad58ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Sat, 27 Oct 2018 15:45:55 +0200 Subject: [PATCH] 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. --- source/eventcore/drivers/timer.d | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/source/eventcore/drivers/timer.d b/source/eventcore/drivers/timer.d index dc090c3..802b12c 100644 --- a/source/eventcore/drivers/timer.d +++ b/source/eventcore/drivers/timer.d @@ -79,7 +79,10 @@ final class LoopTimeoutTimerDriver : EventDriverTimers { foreach (tm; processed_timers) { auto cb = tm.callback; tm.callback = null; - if (cb) cb(tm.id, true); + if (cb) { + cb(tm.id, true); + releaseRef(tm.id); + } } return processed_timers.length > 0; @@ -119,7 +122,10 @@ final class LoopTimeoutTimerDriver : EventDriverTimers { if (!tm.pending) return; TimerCallback2 cb; swap(cb, tm.callback); - if (cb) cb(timer, false); + if (cb) { + cb(timer, false); + releaseRef(timer); + } tm.pending = false; 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."); m_timers[timer].callback = callback; + addRef(timer); } alias wait = EventDriverTimers.wait; @@ -146,6 +153,7 @@ final class LoopTimeoutTimerDriver : EventDriverTimers { auto pt = m_timers[timer]; assert(pt.callback); pt.callback = null; + releaseRef(timer); } final override void addRef(TimerID descriptor) @@ -164,7 +172,20 @@ final class LoopTimeoutTimerDriver : EventDriverTimers { if (descriptor !in m_timers) return true; 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); m_timers.remove(descriptor); () @trusted {