@@ -21,8 +21,8 @@ internal sealed class ProcessRunner
2121 private CancellationTokenRegistration _ctRegistration ;
2222 private readonly StringBuilder _stdOutBuilder ;
2323 private readonly StringBuilder _stdErrBuilder ;
24- private readonly AutoResetEvent _stdOutWaitHandle ;
25- private readonly AutoResetEvent _stdErrWaitHandle ;
24+ private readonly TaskCompletionSource < bool > _stdOutCompletionSource ;
25+ private readonly TaskCompletionSource < bool > _stdErrCompletionSource ;
2626
2727 public ProcessRunner ( IProcess process , TimeSpan timeout , CancellationToken cancellationToken )
2828 {
@@ -31,8 +31,8 @@ public ProcessRunner(IProcess process, TimeSpan timeout, CancellationToken cance
3131 _tcs = new TaskCompletionSource < string > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
3232 _stdOutBuilder = new StringBuilder ( ) ;
3333 _stdErrBuilder = new StringBuilder ( ) ;
34- _stdOutWaitHandle = new AutoResetEvent ( false ) ;
35- _stdErrWaitHandle = new AutoResetEvent ( false ) ;
34+ _stdOutCompletionSource = new TaskCompletionSource < bool > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
35+ _stdErrCompletionSource = new TaskCompletionSource < bool > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
3636
3737 if ( timeout . TotalMilliseconds >= 0 )
3838 {
@@ -45,16 +45,22 @@ public ProcessRunner(IProcess process, TimeSpan timeout, CancellationToken cance
4545 }
4646 }
4747
48- public Task < string > RunAsync ( )
48+ public async Task < string > RunAsync ( )
4949 {
5050 StartProcess ( ) ;
51- return _tcs . Task ;
51+
52+ await _stdOutCompletionSource . Task . ConfigureAwait ( false ) ;
53+ await _stdErrCompletionSource . Task . ConfigureAwait ( false ) ;
54+
55+ return await _tcs . Task . ConfigureAwait ( false ) ;
5256 }
5357
5458 public string Run ( )
5559 {
5660 StartProcess ( ) ;
5761#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult().
62+ _stdOutCompletionSource . Task . GetAwaiter ( ) . GetResult ( ) ;
63+ _stdErrCompletionSource . Task . GetAwaiter ( ) . GetResult ( ) ;
5864 return _tcs . Task . GetAwaiter ( ) . GetResult ( ) ;
5965#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult().
6066 }
@@ -83,9 +89,6 @@ private void StartProcess()
8389
8490 private void HandleExit ( )
8591 {
86- _stdOutWaitHandle . WaitOne ( _timeout ) ;
87- _stdErrWaitHandle . WaitOne ( _timeout ) ;
88-
8992 if ( _process . ExitCode == 0 )
9093 {
9194 TrySetResult ( _stdOutBuilder . ToString ( ) ) ;
@@ -99,7 +102,7 @@ private void HandleStdErrDataReceived(object sender, DataReceivedEventArgsWrappe
99102 {
100103 if ( e . Data is null )
101104 {
102- _stdErrWaitHandle . Set ( ) ;
105+ _stdErrCompletionSource . TrySetResult ( true ) ;
103106 }
104107 else
105108 {
@@ -111,7 +114,7 @@ private void HandleStdOutDataReceived(object sender, DataReceivedEventArgsWrappe
111114 {
112115 if ( e . Data is null )
113116 {
114- _stdOutWaitHandle . Set ( ) ;
117+ _stdOutCompletionSource . TrySetResult ( true ) ;
115118 }
116119 else
117120 {
@@ -153,6 +156,8 @@ private bool TrySetCanceled()
153156 if ( _cancellationToken . IsCancellationRequested )
154157 {
155158 DisposeProcess ( ) ;
159+ _stdOutCompletionSource . TrySetCanceled ( _cancellationToken ) ;
160+ _stdErrCompletionSource . TrySetCanceled ( _cancellationToken ) ;
156161 _tcs . TrySetCanceled ( _cancellationToken ) ;
157162 }
158163
@@ -162,15 +167,15 @@ private bool TrySetCanceled()
162167 private void TrySetException ( Exception exception )
163168 {
164169 DisposeProcess ( ) ;
170+ _stdOutCompletionSource . TrySetResult ( false ) ;
171+ _stdErrCompletionSource . TrySetResult ( false ) ;
165172 _tcs . TrySetException ( exception ) ;
166173 }
167174
168175 private void DisposeProcess ( )
169176 {
170177 _process . OutputDataReceived -= HandleStdOutDataReceived ;
171178 _process . ErrorDataReceived -= HandleStdErrDataReceived ;
172- _stdOutWaitHandle . Dispose ( ) ;
173- _stdErrWaitHandle . Dispose ( ) ;
174179
175180 _process . Dispose ( ) ;
176181 _ctRegistration . Dispose ( ) ;
0 commit comments