Merge pull request #139 from vibe-d/busy_loop_interleave
Fix proper interleaving of busy yield loops inside and outside of tasks.
This commit is contained in:
commit
f558ce6c3f
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue