`startProcessAsync` deadlocks if process exists before calling AwaitEvent
Closed this issue · 0 comments
blumu commented
With the NoTimeout
option, startProcessAsync
can deadlock when waiting for the process to terminate if the process exits before the call to Async.AwaitEvent
:
Repro (extracting minimal code from Diagnostics.fs)
let deadlockRepro =
async {
use instance =
new System.Diagnostics.Process(
StartInfo =
System.Diagnostics.ProcessStartInfo
(
FileName = "notepad.exe",
WorkingDirectory = ".",
Arguments = "",
CreateNoWindow = false,
UseShellExecute = false,
RedirectStandardOutput = false,
WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal,
Verb = "runas"
),
EnableRaisingEvents = true)
let r = instance.Start()
printfn "killing the process"
System.Diagnostics.Process.GetProcessById(instance.Id).Kill()
printfn "waiting for process to exit"
let! waitAsync = Async.AwaitEvent(instance.Exited)
printfn "process exited with code: %d" instance.ExitCode
}
deadlockRepro |> Async.RunSynchronously
Fix:
let startProcessWaitNoHang () =
async {
use instance =
new System.Diagnostics.Process(
StartInfo =
System.Diagnostics.ProcessStartInfo
(
FileName = "notepad.exe",
WorkingDirectory = ".",
Arguments = "",
CreateNoWindow = false,
UseShellExecute = false,
RedirectStandardOutput = false,
WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal,
Verb = "runas"
),
EnableRaisingEvents = true)
let! waitAsync = Async.StartChild(Async.AwaitEvent(instance.Exited))
if not (instance.Start()) then
return raise <| System.InvalidOperationException("Could not start the process")
else
printfn "killing the process"
System.Diagnostics.Process.GetProcessById(instance.Id).Kill()
printfn "waiting for process to exit"
let! _ = waitAsync
printfn "process exited with code: %d" instance.ExitCode
}
startProcessWaitNoHang() |> Async.RunSynchronously