Revert to execute timer callbacks in tasks and add createLeanTimer instead.
Fixes #125.
This commit is contained in:
parent
1a87ee5b3f
commit
03ffe70dc1
|
@ -730,17 +730,18 @@ unittest {
|
||||||
/**
|
/**
|
||||||
Returns a new armed timer.
|
Returns a new armed timer.
|
||||||
|
|
||||||
Note that timers can only work if an event loop is running.
|
Note that timers can only work if an event loop is running, explicitly or
|
||||||
|
implicitly by running a blocking operation, such as `sleep` or `File.read`.
|
||||||
|
|
||||||
Params:
|
Params:
|
||||||
timeout = Determines the minimum amount of time that elapses before the timer fires.
|
timeout = Determines the minimum amount of time that elapses before the timer fires.
|
||||||
callback = This delegate will be called when the timer fires
|
callback = If non-`null`, this delegate will be called when the timer fires
|
||||||
periodic = Speficies if the timer fires repeatedly or only once
|
periodic = Speficies if the timer fires repeatedly or only once
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Returns a Timer object that can be used to identify and modify the timer.
|
Returns a Timer object that can be used to identify and modify the timer.
|
||||||
|
|
||||||
See_also: createTimer
|
See_also: `createTimer`
|
||||||
*/
|
*/
|
||||||
Timer setTimer(Duration timeout, Timer.Callback callback, bool periodic = false)
|
Timer setTimer(Duration timeout, Timer.Callback callback, bool periodic = false)
|
||||||
@safe nothrow {
|
@safe nothrow {
|
||||||
|
@ -777,14 +778,53 @@ Timer setTimer(Duration timeout, void delegate() callback, bool periodic = false
|
||||||
}, periodic);
|
}, periodic);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Creates a new timer without arming it.
|
|
||||||
|
|
||||||
See_also: setTimer
|
/** Creates a new timer without arming it.
|
||||||
|
|
||||||
|
Each time `callback` gets invoked, it will be run inside of a newly started
|
||||||
|
task.
|
||||||
|
|
||||||
|
Params:
|
||||||
|
callback = If non-`null`, this delegate will be called when the timer
|
||||||
|
fires
|
||||||
|
|
||||||
|
See_also: `createLeanTimer`, `setTimer`
|
||||||
*/
|
*/
|
||||||
Timer createTimer(void delegate() nothrow @safe callback)
|
Timer createTimer(void delegate() nothrow @safe callback = null)
|
||||||
@safe nothrow {
|
@safe nothrow {
|
||||||
return Timer(eventDriver.timers.create, callback);
|
static struct C {
|
||||||
|
void delegate() nothrow @safe callback;
|
||||||
|
void opCall() nothrow @safe { runTask(callback); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
C c = {callback};
|
||||||
|
return createLeanTimer(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return createLeanTimer!(Timer.Callback)(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Creates a new timer with a lean callback mechanism.
|
||||||
|
|
||||||
|
In contrast to the standard `createTimer`, `callback` will not be called
|
||||||
|
in a new task, but is instead called directly in the context of the event
|
||||||
|
loop.
|
||||||
|
|
||||||
|
For this reason, the supplied callback is not allowed to perform any
|
||||||
|
operation that needs to block/yield execution. In this case, `runTask`
|
||||||
|
needs to be used explicitly to perform the operation asynchronously.
|
||||||
|
|
||||||
|
Additionally, `callback` can carry arbitrary state without requiring a heap
|
||||||
|
allocation.
|
||||||
|
|
||||||
|
See_also: `createTimer`
|
||||||
|
*/
|
||||||
|
Timer createLeanTimer(CALLABLE)(CALLABLE callback)
|
||||||
|
if (is(typeof(() @safe nothrow { callback(); } ())))
|
||||||
|
{
|
||||||
|
return Timer.create(eventDriver.timers.create(), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1031,16 +1071,22 @@ struct Timer {
|
||||||
|
|
||||||
@safe:
|
@safe:
|
||||||
|
|
||||||
private this(TimerID id, Callback callback)
|
private static Timer create(CALLABLE)(TimerID id, CALLABLE callback)
|
||||||
nothrow {
|
nothrow {
|
||||||
assert(id != TimerID.init, "Invalid timer ID.");
|
assert(id != TimerID.init, "Invalid timer ID.");
|
||||||
m_driver = eventDriver;
|
|
||||||
m_id = id;
|
|
||||||
|
|
||||||
if (callback) {
|
Timer ret;
|
||||||
m_driver.timers.userData!Callback(m_id) = callback;
|
ret.m_driver = eventDriver;
|
||||||
m_driver.timers.wait(m_id, &TimerCallbackHandler.instance.handle);
|
ret.m_id = id;
|
||||||
}
|
|
||||||
|
static if (is(typeof(!callback)))
|
||||||
|
if (!callback)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret.m_driver.timers.userData!CALLABLE(id) = callback;
|
||||||
|
ret.m_driver.timers.wait(id, &TimerCallbackHandler!CALLABLE.instance.handle);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
this(this)
|
this(this)
|
||||||
|
@ -1078,6 +1124,8 @@ struct Timer {
|
||||||
|
|
||||||
/** Waits until the timer fires.
|
/** Waits until the timer fires.
|
||||||
|
|
||||||
|
This method may only be used if no timer callback has been specified.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
`true` is returned $(I iff) the timer was fired.
|
`true` is returned $(I iff) the timer was fired.
|
||||||
*/
|
*/
|
||||||
|
@ -1094,12 +1142,14 @@ struct Timer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TimerCallbackHandler {
|
/// private
|
||||||
|
struct TimerCallbackHandler(CALLABLE) {
|
||||||
static TimerCallbackHandler instance;
|
static TimerCallbackHandler instance;
|
||||||
void handle(TimerID timer, bool fired)
|
void handle(TimerID timer, bool fired)
|
||||||
@safe nothrow {
|
@safe nothrow {
|
||||||
if (fired) {
|
if (fired) {
|
||||||
auto cb = eventDriver.timers.userData!(Timer.Callback)(timer);
|
auto cb = eventDriver.timers.userData!CALLABLE(timer);
|
||||||
|
auto l = yieldLock();
|
||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue