Fix proper interleaving of busy yield loops inside and outside of tasks.

This commit is contained in:
Sönke Ludwig 2019-03-06 12:35:37 +01:00
parent bfcf08def0
commit cae9f28885

View file

@ -662,10 +662,24 @@ void yield()
} else { } else {
// Let yielded tasks execute // Let yielded tasks execute
assert(TaskFiber.getThis().m_yieldLockCount == 0, "May not yield within an active yieldLock()!"); assert(TaskFiber.getThis().m_yieldLockCount == 0, "May not yield within an active yieldLock()!");
() @safe nothrow { performIdleProcessing(true); } (); () @safe nothrow { performIdleProcessingOnce(true); } ();
} }
} }
unittest {
size_t ti;
auto t = runTask({
for (ti = 0; ti < 10; ti++)
yield();
});
foreach (i; 0 .. 5) yield();
assert(ti > 0 && ti < 10, "Task did not interleave with yield loop outside of task");
t.join();
assert(ti == 10);
}
/** /**
Suspends the execution of the calling task until `switchToTask` is called Suspends the execution of the calling task until `switchToTask` is called
@ -1244,31 +1258,39 @@ package(vibe) void performIdleProcessing(bool force_process_events = false)
@safe nothrow { @safe nothrow {
bool again = !getExitFlag(); bool again = !getExitFlag();
while (again) { while (again) {
if (force_process_events) { again = performIdleProcessingOnce(force_process_events);
auto er = eventDriver.core.processEvents(0.seconds); force_process_events = true;
if (er.among!(ExitReason.exited, ExitReason.outOfWaiters) && s_scheduler.scheduledTaskCount == 0) {
if (s_eventLoopRunning) {
logDebug("Setting exit flag due to driver signalling exit: %s", er);
s_exitEventLoop = true;
}
return;
}
} else force_process_events = true;
if (s_idleHandler)
again = s_idleHandler();
else again = false;
again = (s_scheduler.schedule() == ScheduleStatus.busy || again) && !getExitFlag();
} }
if (s_scheduler.scheduledTaskCount) logDebug("Exiting from idle processing although there are still yielded tasks"); if (s_scheduler.scheduledTaskCount) logDebug("Exiting from idle processing although there are still yielded tasks");
if (s_exitEventLoop) return;
if (!s_ignoreIdleForGC && s_gcTimer) { if (!s_ignoreIdleForGC && s_gcTimer) {
s_gcTimer.rearm(s_gcCollectTimeout); s_gcTimer.rearm(s_gcCollectTimeout);
} else s_ignoreIdleForGC = false; } else s_ignoreIdleForGC = false;
} }
private bool performIdleProcessingOnce(bool process_events)
@safe nothrow {
if (process_events) {
auto er = eventDriver.core.processEvents(0.seconds);
if (er.among!(ExitReason.exited, ExitReason.outOfWaiters) && s_scheduler.scheduledTaskCount == 0) {
if (s_eventLoopRunning) {
logDebug("Setting exit flag due to driver signalling exit: %s", er);
s_exitEventLoop = true;
}
return false;
}
}
bool again;
if (s_idleHandler)
again = s_idleHandler();
return (s_scheduler.schedule() == ScheduleStatus.busy || again) && !getExitFlag();
}
private struct ThreadContext { private struct ThreadContext {
Thread thread; Thread thread;