Add setTaskCreationCallback() for better remote debugger integration.

This commit is contained in:
Sönke Ludwig 2017-07-16 22:07:59 +02:00
parent 719c62d6c9
commit 4f69b1eaf3
2 changed files with 43 additions and 3 deletions

View file

@ -373,6 +373,13 @@ package Task runTask_internal(alias TFI_SETUP)()
f.bumpTaskCounter();
auto handle = f.task();
debug if (TaskFiber.ms_taskCreationCallback) {
TaskCreationInfo info;
info.handle = handle;
info.functionPointer = () @trusted { return cast(void*)f.m_taskFunc.functionPointer; } ();
() @trusted { TaskFiber.ms_taskCreationCallback(info); } ();
}
debug if (TaskFiber.ms_taskEventCallback) {
() @trusted { TaskFiber.ms_taskEventCallback(TaskEvent.preStart, handle); } ();
}
@ -916,6 +923,21 @@ void setTaskEventCallback(TaskEventCallback func)
debug TaskFiber.ms_taskEventCallback = func;
}
/**
Sets a callback that is invoked whenever new task is created.
The callback is guaranteed to be invoked before the one set by
`setTaskEventCallback` for the same task handle.
This function is useful mostly for implementing debuggers that
analyze the life time of tasks, including task switches. Note that
the callback will only be called for debug builds.
*/
void setTaskCreationCallback(TaskCreationCallback func)
{
debug TaskFiber.ms_taskCreationCallback = func;
}
/**
A version string representing the current vibe version

View file

@ -262,7 +262,13 @@ enum TaskEvent {
fail /// Ended with an exception
}
struct TaskCreationInfo {
Task handle;
const(void)* functionPointer;
}
alias TaskEventCallback = void function(TaskEvent, Task) nothrow;
alias TaskCreationCallback = void function(ref TaskCreationInfo) nothrow @safe;
/**
The maximum combined size of all parameters passed to a task delegate
@ -314,6 +320,7 @@ final package class TaskFiber : Fiber {
package TaskFuncInfo m_taskFunc;
package __gshared size_t ms_taskStackSize = defaultTaskStackSize;
package __gshared debug TaskEventCallback ms_taskEventCallback;
package __gshared debug TaskCreationCallback ms_taskCreationCallback;
this()
@trusted nothrow {
@ -323,9 +330,7 @@ final package class TaskFiber : Fiber {
static TaskFiber getThis()
@safe nothrow {
auto f = () @trusted nothrow {
return Fiber.getThis();
} ();
auto f = () @trusted nothrow { return Fiber.getThis(); } ();
if (auto tf = cast(TaskFiber)f) return tf;
if (!ms_globalDummyFiber) ms_globalDummyFiber = new TaskFiber;
return ms_globalDummyFiber;
@ -508,6 +513,7 @@ package struct TaskFuncInfo {
void function(ref TaskFuncInfo) func;
void[2*size_t.sizeof] callable;
void[maxTaskParameterSize] args;
debug ulong functionPointer;
void set(CALLABLE, ARGS...)(ref CALLABLE callable, ref ARGS args)
{
@ -525,6 +531,8 @@ package struct TaskFuncInfo {
"The arguments passed to run(Worker)Task must not exceed "~
maxTaskParameterSize.to!string~" bytes in total size: "~TARGS.sizeof.stringof~" bytes");
debug functionPointer = callPointer(callable);
static void callDelegate(ref TaskFuncInfo tfi) {
assert(tfi.func is &callDelegate, "Wrong callDelegate called!?");
@ -584,6 +592,16 @@ package struct TaskFuncInfo {
}
}
private ulong callPointer(C)(ref C callable)
@trusted nothrow @nogc {
alias IP = ulong;
static if (is(C == function)) return cast(IP)cast(void*)callable;
else static if (is(C == delegate)) return cast(IP)callable.funcptr;
else static if (is(typeof(&callable.opCall) == function)) return cast(IP)cast(void*)&callable.opCall;
else static if (is(typeof(&callable.opCall) == delegate)) return cast(IP)(&callable.opCall).funcptr;
else return cast(IP)&callable;
}
package struct TaskScheduler {
import eventcore.driver : ExitReason;
import eventcore.core : eventDriver;