Browse Source

Synchronize output buffers. (#1290)

main-publicPoolNames
Phillip Hoff 5 years ago
committed by GitHub
parent
commit
0e578cbe66
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      src/Microsoft.Tye.Core/ProcessUtil.cs

49
src/Microsoft.Tye.Core/ProcessUtil.cs

@ -76,6 +76,27 @@ namespace Microsoft.Tye
} }
} }
var outputLock = new SpinLock();
void WithOutputLock(Action action)
{
bool gotLock = false;
try
{
outputLock.Enter(ref gotLock);
action();
}
finally
{
if (gotLock)
{
outputLock.Exit();
}
}
}
var outputBuilder = new StringBuilder(); var outputBuilder = new StringBuilder();
process.OutputDataReceived += (_, e) => process.OutputDataReceived += (_, e) =>
{ {
@ -90,7 +111,7 @@ namespace Microsoft.Tye
} }
else else
{ {
outputBuilder.AppendLine(e.Data); WithOutputLock(() => outputBuilder.AppendLine(e.Data));
} }
}; };
@ -108,7 +129,7 @@ namespace Microsoft.Tye
} }
else else
{ {
errorBuilder.AppendLine(e.Data); WithOutputLock(() => errorBuilder.AppendLine(e.Data));
} }
}; };
@ -129,15 +150,21 @@ namespace Microsoft.Tye
process.WaitForExit(ProcessExitTimeoutMs); process.WaitForExit(ProcessExitTimeoutMs);
} }
if (throwOnError && process.ExitCode != 0) // NOTE: If WaitForExit() returns false, more output may be written,
{ // so we must synchronize access to the output StringBuilders.
processLifetimeTask.TrySetException(new InvalidOperationException($"Command {filename} {arguments} returned exit code {process.ExitCode}. Standard error: \"{errorBuilder.ToString()}\""));
} WithOutputLock(
else () =>
{ {
// Since the process has exited, no additional data will be written to either output buffer or error buffer, it's thread-safe to call ToString() on both outputBuilder and errorBuilder. if (throwOnError && process.ExitCode != 0)
processLifetimeTask.TrySetResult(new ProcessResult(outputBuilder.ToString(), errorBuilder.ToString(), process.ExitCode)); {
} processLifetimeTask.TrySetException(new InvalidOperationException($"Command {filename} {arguments} returned exit code {process.ExitCode}. Standard error: \"{errorBuilder.ToString()}\""));
}
else
{
processLifetimeTask.TrySetResult(new ProcessResult(outputBuilder.ToString(), errorBuilder.ToString(), process.ExitCode));
}
});
}; };
// lock ensures we're reading output when WaitForExit is called in process.Exited event. // lock ensures we're reading output when WaitForExit is called in process.Exited event.

Loading…
Cancel
Save