diff --git a/CHANGELOG.md b/CHANGELOG.md index 814fe02..fffe61b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,14 @@ - Simplified worker task logic by avoiding an explicit event loop - [pull #95][issue95] - Fixed an issue in `WindowsPath`, where an empty path was converted to "/" when cast to another path type - [pull #91][issue91] - Fixed two hang issues in `TaskPool` causing the worker task processing to possibly hang at shutdown or to temporarily hang during run time - [pull #96][issue96] +- Fixed internal timer callback tasks leaking memory - [issue #86][issue86], [pull #98][issue98] [issue91]: https://github.com/vibe-d/vibe-core/issues/91 [issue92]: https://github.com/vibe-d/vibe-core/issues/92 [issue95]: https://github.com/vibe-d/vibe-core/issues/95 [issue96]: https://github.com/vibe-d/vibe-core/issues/96 [issue97]: https://github.com/vibe-d/vibe-core/issues/97 +[issue98]: https://github.com/vibe-d/vibe-core/issues/98 1.4.3 - 2018-09-03 diff --git a/dub.sdl b/dub.sdl index dcefdc2..f0cdd03 100644 --- a/dub.sdl +++ b/dub.sdl @@ -4,7 +4,7 @@ authors "Sönke Ludwig" copyright "Copyright © 2016-2018, rejectedsoftware e.K." license "MIT" -dependency "eventcore" version="~>0.8.32" +dependency "eventcore" version="~>0.8.39" dependency "stdx-allocator" version="~>2.77.0" targetName "vibe_core" diff --git a/source/vibe/core/core.d b/source/vibe/core/core.d index 41202e1..abdfa12 100644 --- a/source/vibe/core/core.d +++ b/source/vibe/core/core.d @@ -742,7 +742,7 @@ unittest { See_also: createTimer */ -Timer setTimer(Duration timeout, void delegate() nothrow @safe callback, bool periodic = false) +Timer setTimer(Duration timeout, Timer.Callback callback, bool periodic = false) @safe nothrow { auto tm = createTimer(callback); tm.rearm(timeout, periodic); @@ -784,16 +784,7 @@ Timer setTimer(Duration timeout, void delegate() callback, bool periodic = false */ Timer createTimer(void delegate() nothrow @safe callback) @safe nothrow { - auto ret = Timer(eventDriver.timers.create()); - if (callback !is null) { - runTask((void delegate() nothrow @safe cb, Timer tm) { - while (!tm.unique || tm.pending) { - tm.wait(); - cb(); - } - }, callback, ret); - } - return ret; + return Timer(eventDriver.timers.create, callback); } @@ -1036,13 +1027,20 @@ struct Timer { debug uint m_magicNumber = 0x4d34f916; } + alias Callback = void delegate() @safe nothrow; + @safe: - private this(TimerID id) + private this(TimerID id, Callback callback) nothrow { assert(id != TimerID.init, "Invalid timer ID."); m_driver = eventDriver; m_id = id; + + if (callback) { + m_driver.timers.userData!Callback(m_id) = callback; + m_driver.timers.wait(m_id, &TimerCallbackHandler.instance.handle); + } } this(this) @@ -1054,8 +1052,7 @@ struct Timer { ~this() nothrow { debug assert(m_magicNumber == 0x4d34f916, "Timer corrupted."); - if (m_driver) - releaseHandle!"timers"(m_id, () @trusted { return cast(shared)m_driver; } ()); + if (m_driver) releaseHandle!"timers"(m_id, () @trusted { return cast(shared)m_driver; } ()); } /// True if the timer is yet to fire. @@ -1080,13 +1077,34 @@ struct Timer { void stop() nothrow { if (m_driver) m_driver.timers.stop(m_id); } /** Waits until the timer fires. + + Returns: + `true` is returned $(I iff) the timer was fired. */ - void wait() + bool wait() { - asyncAwait!(TimerCallback, + auto cb = m_driver.timers.userData!Callback(m_id); + assert(cb is null, "Cannot wait on a timer that was created with a callback."); + + auto res = asyncAwait!(TimerCallback2, cb => m_driver.timers.wait(m_id, cb), cb => m_driver.timers.cancelWait(m_id) ); + return res[1]; + } +} + +struct TimerCallbackHandler { + static TimerCallbackHandler instance; + void handle(TimerID timer, bool fired) + @safe nothrow { + if (fired) { + auto cb = eventDriver.timers.userData!(Timer.Callback)(timer); + cb(); + } + + if (!eventDriver.timers.isUnique(timer)) + eventDriver.timers.wait(timer, &handle); } }