diff --git a/src/DurableEngine/OrchestrationInvoker.cs b/src/DurableEngine/OrchestrationInvoker.cs
index ae58b15..e9841e6 100644
--- a/src/DurableEngine/OrchestrationInvoker.cs
+++ b/src/DurableEngine/OrchestrationInvoker.cs
@@ -76,7 +76,7 @@ internal Hashtable Invoke(IPowerShellServices powerShellServices)
while (true)
{
// block this thread until user-code thread (the PS orchestrator) invokes a DF CmdLet or completes.
- var orchestratorReturned = context.SharedMemory.YieldToUserCodeThread(orchestratorReturnedHandle);
+ var orchestratorReturned = context.SharedMemory.WaitForInvokerThreadTurn(orchestratorReturnedHandle);
if (orchestratorReturned)
{
// The PS orchestrator has a return value, there's no more DF APIs to await.
@@ -109,6 +109,12 @@ internal Hashtable Invoke(IPowerShellServices powerShellServices)
await task.GetDTFxTask();
} // Exceptions are ignored at this point, they will be re-surfaced by the PS code if left unhandled.
catch { }
+
+ // Wake up user-code thread. For a small moment, both the user code thread and the invoker thread
+ // will be running at the same time.
+ // However, the invoker thread will block itself again at the start of the next loop until the user-code
+ // thread yields control.
+ context.SharedMemory.WakeUserCodeThread();
}
};
diff --git a/src/DurableEngine/SharedMemory.cs b/src/DurableEngine/SharedMemory.cs
index 20d02a1..c5012a6 100644
--- a/src/DurableEngine/SharedMemory.cs
+++ b/src/DurableEngine/SharedMemory.cs
@@ -40,25 +40,16 @@ public void YieldToInvokerThread()
{
// Wake invoker thread.
invokerThreadTurn.Set();
-
- // Block user-code thread.
- userCodeThreadTurn.Reset();
userCodeThreadTurn.WaitOne();
}
///
- /// Blocks Orchestration-invoker thread, wakes up user-code thread.
- /// This is usually used after the invoker has a result for the PS orchestrator.
+ /// Blocks Orchestration-invoker thread until the user-code thread completes or yields.
///
/// The WaitHandle tracking if the user-code thread completed.
/// True if the user-code thread completed, False if it requests an API to be awaited.
- public bool YieldToUserCodeThread(WaitHandle completionHandle)
+ public bool WaitForInvokerThreadTurn(WaitHandle completionHandle)
{
- // Wake user-code thread
- userCodeThreadTurn.Set();
-
- // Get invoker thread ready to block
- invokerThreadTurn.Reset();
// Wake up when either the user-code returns, or when we're yielded-to for `await`'ing.
var index = WaitHandle.WaitAny(new[] { completionHandle, invokerThreadTurn });
@@ -67,13 +58,12 @@ public bool YieldToUserCodeThread(WaitHandle completionHandle)
}
///
- /// Blocks user code thread if the orchestrator-invoker thread is currently running.
- /// This guarantees that the user-code thread and the orchestration-invoker thread run one
- /// at a time after this point.
+ /// Wakes up the user-code thread without blocking the invoker thread.
+ /// The invoker thread should block itself afterwards to prevent races.
///
- public void GuaranteeUserCodeTurn()
+ public void WakeUserCodeThread()
{
- userCodeThreadTurn.WaitOne();
+ userCodeThreadTurn.Set();
}
}
}
\ No newline at end of file
diff --git a/src/DurableEngine/Tasks/DurableTask.cs b/src/DurableEngine/Tasks/DurableTask.cs
index 0e1604a..1dd4b72 100644
--- a/src/DurableEngine/Tasks/DurableTask.cs
+++ b/src/DurableEngine/Tasks/DurableTask.cs
@@ -49,10 +49,6 @@ internal OrchestrationAction GetOrCreateAction()
/// Function to write an exception to the pipeline.
public void Execute(Action