From ef7c19d3734f67cae011006320d105c2b0c547af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Tue, 26 Sep 2017 15:18:20 +0200 Subject: [PATCH 1/3] Add test for issue #25 - periodic timers overlapping single-shot timers. --- tests/issue-25-periodic-timers.d | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tests/issue-25-periodic-timers.d diff --git a/tests/issue-25-periodic-timers.d b/tests/issue-25-periodic-timers.d new file mode 100644 index 0000000..a0156cb --- /dev/null +++ b/tests/issue-25-periodic-timers.d @@ -0,0 +1,68 @@ +/++ dub.sdl: + name "test" + dependency "eventcore" path=".." ++/ +module test; + +import eventcore.core; +import std.datetime : Clock, SysTime, UTC; +import std.stdio : writefln; +import core.time : Duration, msecs; + +SysTime s_startTime; +int s_cnt = 0; +bool s_done; + +void main() +{ + s_startTime = Clock.currTime(UTC()); + + bool timer1fired = false; + + // first timer: one-shot 200ms + auto tm = eventDriver.timers.create(); + eventDriver.timers.wait(tm, (tm) nothrow @safe { + scope (failure) assert(false); + writefln("First timer"); + + auto dur = Clock.currTime(UTC()) - s_startTime; + assert(dur > 200.msecs); + assert(dur < 220.msecs); + + timer1fired = true; + }); + eventDriver.timers.set(tm, 200.msecs, 0.msecs); + + // second timer repeating 100ms, 3 times + auto tm2 = eventDriver.timers.create(); + eventDriver.timers.set(tm2, 100.msecs, 100.msecs); + void periodicCallback(TimerID timer) nothrow @safe { + try { + writefln("Second timer"); + + auto dur = Clock.currTime(UTC()) - s_startTime; + s_cnt++; + assert(dur > 100.msecs * s_cnt); + assert(dur < 100.msecs * s_cnt + 20.msecs); + assert(s_cnt <= 3); + + if (s_cnt == 3) { + s_done = true; + eventDriver.timers.stop(timer); + assert(timer1fired, "Timer 1 didn't fire within 300ms"); + } else eventDriver.timers.wait(tm2, &periodicCallback); + } catch (Exception e) { + assert(false, e.msg); + } + } + + eventDriver.timers.wait(tm2, &periodicCallback); + + + ExitReason er; + do er = eventDriver.core.processEvents(Duration.max); + while (er == ExitReason.idle); + assert(er == ExitReason.outOfWaiters); + assert(s_done); + s_done = false; +} From 60407b783b8c64928b6cce2d4cc075467ca621d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Tue, 26 Sep 2017 15:42:03 +0200 Subject: [PATCH 2/3] Fix re-enqueuing of periodic timers. Fixes #25. Periodic timers were first re-enqueued and then removed, effectively causing them to stay at their old position, cutting off the tail of the timer queue. --- source/eventcore/drivers/timer.d | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/eventcore/drivers/timer.d b/source/eventcore/drivers/timer.d index a9bbfba..15277ea 100644 --- a/source/eventcore/drivers/timer.d +++ b/source/eventcore/drivers/timer.d @@ -51,14 +51,15 @@ final class LoopTimeoutTimerDriver : EventDriverTimers { if (tm.repeatDuration > 0) { do tm.timeout += tm.repeatDuration; while (tm.timeout <= stdtime); - enqueueTimer(tm); } else tm.pending = false; m_firedTimers ~= tm; } - // NOTE: this isn't yet verified to work under all circumstances - foreach (tm; m_firedTimers) + foreach (tm; m_firedTimers) { m_timerQueue.remove(tm); + if (tm.repeatDuration > 0) + enqueueTimer(tm); + } foreach (tm; m_firedTimers) { auto cb = tm.callback; From 8799b7b01eb163af8dfce0c6ee630e9345103b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Tue, 26 Sep 2017 15:42:23 +0200 Subject: [PATCH 3/3] Add assertion. --- source/eventcore/internal/dlist.d | 1 + 1 file changed, 1 insertion(+) diff --git a/source/eventcore/internal/dlist.d b/source/eventcore/internal/dlist.d index 5186fc8..8358e5d 100644 --- a/source/eventcore/internal/dlist.d +++ b/source/eventcore/internal/dlist.d @@ -59,6 +59,7 @@ struct StackDList(T) { void insertAfter(T* item, T* after) { + assert(!item.prev && !item.next); if (!after) insertBack(item); else { item.prev = after;