diff --git a/source/vibe/core/task.d b/source/vibe/core/task.d index ad8f704..7950da9 100644 --- a/source/vibe/core/task.d +++ b/source/vibe/core/task.d @@ -362,7 +362,7 @@ final package class TaskFiber : Fiber { import std.algorithm.mutation : swap; import std.concurrency : Tid, thisTid; import std.encoding : sanitize; - import vibe.core.core : isEventLoopRunning, recycleFiber, taskScheduler, yield; + import vibe.core.core : isEventLoopRunning, recycleFiber, taskScheduler, yield, yieldLock; version (VibeDebugCatchAll) alias UncaughtException = Throwable; else alias UncaughtException = Exception; @@ -413,6 +413,17 @@ final package class TaskFiber : Fiber { this.tidInfo.ident = Tid.init; // clear message box debug (VibeTaskLog) logTrace("Notifying joining tasks."); + + // Issue #161: This fiber won't be resumed before the next task + // is assigned, because it is already marked as de-initialized. + // Since ManualEvent.emit() will need to switch tasks, this + // would mean that only the first waiter is notified before + // this fiber gets a new task assigned. + // Using a yield lock forces all corresponding tasks to be + // enqueued into the schedule queue and resumed in sequence + // at the end of the scope. + auto l = yieldLock(); + m_onExit.emit(); // make sure that the task does not get left behind in the yielder queue if terminated during yield() @@ -723,7 +734,7 @@ package struct TaskScheduler { auto t = Task.getThis(); if (t == Task.init) return; // not really a task -> no-op auto tf = () @trusted { return t.taskFiber; } (); - debug (VibeTaskLog) logTrace("Yielding (interrupt=%s)", tf.m_interrupt); + debug (VibeTaskLog) logTrace("Yielding (interrupt=%s)", () @trusted { return (cast(shared)tf).getTaskStatus().interrupt; } ()); tf.handleInterrupt(); if (tf.m_queue !is null) return; // already scheduled to be resumed m_taskQueue.insertBack(tf); diff --git a/tests/issue-161-multiple-joiners.d b/tests/issue-161-multiple-joiners.d new file mode 100644 index 0000000..c0ebc78 --- /dev/null +++ b/tests/issue-161-multiple-joiners.d @@ -0,0 +1,31 @@ +/+ dub.sdl: + name "tests" + dependency "vibe-core" path=".." + debugVersions "VibeTaskLog" "VibeAsyncLog" ++/ +module tests; + +import vibe.core.core; +import vibe.core.log; +import vibe.core.sync; +import core.time; +import core.stdc.stdlib : exit; + + +void main() +{ + setTimer(5.seconds, { logError("Test has hung."); exit(1); }); + + Task t; + + runTask({ + t = runTask({ sleep(100.msecs); }); + t.join(); + }); + + yield(); + + assert(t && t.running); + + t.join(); +}