Add TaskSwitchPriority to control the priority to use when transferring execution.
This commit is contained in:
parent
d07c2f02e6
commit
1eebe7a9ce
|
@ -429,7 +429,7 @@ package Task runTask_internal(alias TFI_SETUP)()
|
|||
() @trusted { TaskFiber.ms_taskEventCallback(TaskEvent.preStart, handle); } ();
|
||||
}
|
||||
|
||||
s_scheduler.switchTo(handle, TaskFiber.getThis().m_yieldLockCount > 0 ? Flag!"defer".yes : Flag!"defer".no);
|
||||
switchToTask(handle);
|
||||
|
||||
debug if (TaskFiber.ms_taskEventCallback) {
|
||||
() @trusted { TaskFiber.ms_taskEventCallback(TaskEvent.postStart, handle); } ();
|
||||
|
@ -808,13 +808,27 @@ void hibernate(scope void delegate() @safe nothrow on_interrupt = null)
|
|||
This function can be used in conjunction with `hibernate` to wake up a
|
||||
task. The task must live in the same thread as the caller.
|
||||
|
||||
See_Also: `hibernate`
|
||||
If no priority is specified, `TaskSwitchPriority.prioritized` or
|
||||
`TaskSwitchPriority.immediate` will be used, depending on whether a
|
||||
yield lock is currently active.
|
||||
|
||||
Note that it is illegal to use `TaskSwitchPriority.immediate` if a yield
|
||||
lock is active.
|
||||
|
||||
This function must only be called on tasks that belong to the calling
|
||||
thread and have previously been hibernated!
|
||||
|
||||
See_Also: `hibernate`, `yieldLock`
|
||||
*/
|
||||
void switchToTask(Task t)
|
||||
@safe nothrow {
|
||||
import std.typecons : Yes, No;
|
||||
auto defer = TaskFiber.getThis().m_yieldLockCount > 0 ? Yes.defer : No.defer;
|
||||
s_scheduler.switchTo(t, defer);
|
||||
auto defer = TaskFiber.getThis().m_yieldLockCount > 0;
|
||||
s_scheduler.switchTo(t, defer ? TaskSwitchPriority.prioritized : TaskSwitchPriority.immediate);
|
||||
}
|
||||
/// ditto
|
||||
void switchToTask(Task t, TaskSwitchPriority priority)
|
||||
@safe nothrow {
|
||||
s_scheduler.switchTo(t, priority);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -558,8 +558,8 @@ final package class TaskFiber : Fiber {
|
|||
if (caller.m_thread is m_thread) {
|
||||
auto thisus = () @trusted { return cast()this; } ();
|
||||
debug (VibeTaskLog) logTrace("Resuming task with interrupt flag.");
|
||||
auto defer = caller.m_yieldLockCount > 0 ? Yes.defer : No.defer;
|
||||
taskScheduler.switchTo(thisus.task, defer);
|
||||
auto defer = caller.m_yieldLockCount > 0;
|
||||
taskScheduler.switchTo(thisus.task, defer ? TaskSwitchPriority.prioritized : TaskSwitchPriority.immediate);
|
||||
} else {
|
||||
debug (VibeTaskLog) logTrace("Set interrupt flag on task without resuming.");
|
||||
}
|
||||
|
@ -642,6 +642,25 @@ final package class TaskFiber : Fiber {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/** Controls the priority to use for switching execution to a task.
|
||||
*/
|
||||
enum TaskSwitchPriority {
|
||||
/** Rescheduled according to the tasks priority
|
||||
*/
|
||||
normal,
|
||||
|
||||
/** Rescheduled with maximum priority.
|
||||
|
||||
The task will resume as soon as the current task yields.
|
||||
*/
|
||||
prioritized,
|
||||
|
||||
/** Switch to the task immediately.
|
||||
*/
|
||||
immediate
|
||||
}
|
||||
|
||||
package struct TaskFuncInfo {
|
||||
void function(ref TaskFuncInfo) func;
|
||||
void[2*size_t.sizeof] callable;
|
||||
|
@ -894,7 +913,7 @@ package struct TaskScheduler {
|
|||
This forces immediate execution of the specified task. After the tasks finishes or yields,
|
||||
the calling task will continue execution.
|
||||
*/
|
||||
void switchTo(Task t, Flag!"defer" defer = No.defer)
|
||||
void switchTo(Task t, TaskSwitchPriority priority)
|
||||
{
|
||||
auto thist = Task.getThis();
|
||||
|
||||
|
@ -905,13 +924,16 @@ package struct TaskScheduler {
|
|||
|
||||
auto tf = () @trusted { return t.taskFiber; } ();
|
||||
if (tf.m_queue) {
|
||||
// don't reset the position of already scheduled tasks
|
||||
if (priority == TaskSwitchPriority.normal) return;
|
||||
|
||||
debug (VibeTaskLog) logTrace("Task to switch to is already scheduled. Moving to front of queue.");
|
||||
assert(tf.m_queue is &m_taskQueue, "Task is already enqueued, but not in the main task queue.");
|
||||
m_taskQueue.remove(tf);
|
||||
assert(!tf.m_queue, "Task removed from queue, but still has one set!?");
|
||||
}
|
||||
|
||||
if (thist == Task.init && defer == No.defer) {
|
||||
if (thist == Task.init && priority == TaskSwitchPriority.immediate) {
|
||||
assert(TaskFiber.getThis().m_yieldLockCount == 0, "Cannot yield within an active yieldLock()!");
|
||||
debug (VibeTaskLog) logTrace("switch to task from global context");
|
||||
resumeTask(t);
|
||||
|
@ -921,12 +943,20 @@ package struct TaskScheduler {
|
|||
assert(!thistf || !thistf.m_queue, "Calling task is running, but scheduled to be resumed!?");
|
||||
|
||||
debug (VibeTaskLog) logDebugV("Switching tasks (%s already in queue)", m_taskQueue.length);
|
||||
if (defer) {
|
||||
m_taskQueue.insertFront(tf);
|
||||
} else {
|
||||
m_taskQueue.insertFront(thistf);
|
||||
m_taskQueue.insertFront(tf);
|
||||
doYield(thist);
|
||||
final switch (priority) {
|
||||
case TaskSwitchPriority.normal:
|
||||
reschedule(tf);
|
||||
break;
|
||||
case TaskSwitchPriority.prioritized:
|
||||
tf.m_dynamicPriority = uint.max;
|
||||
reschedule(tf);
|
||||
break;
|
||||
case TaskSwitchPriority.immediate:
|
||||
tf.m_dynamicPriority = uint.max;
|
||||
m_taskQueue.insertFront(thistf);
|
||||
m_taskQueue.insertFront(tf);
|
||||
doYield(thist);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -994,7 +1024,7 @@ package struct TaskScheduler {
|
|||
}
|
||||
}
|
||||
|
||||
private void doYieldAndReschedule(Task task)
|
||||
private void reschedule(TaskFiber tf)
|
||||
{
|
||||
import std.algorithm.comparison : min;
|
||||
|
||||
|
@ -1009,6 +1039,13 @@ package struct TaskScheduler {
|
|||
t.m_dynamicPriority += min(t.m_staticPriority, uint.max - t.m_dynamicPriority);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private void doYieldAndReschedule(Task task)
|
||||
{
|
||||
auto tf = () @trusted { return task.taskFiber; } ();
|
||||
|
||||
reschedule(tf);
|
||||
|
||||
doYield(task);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue