@@ -10,9 +10,12 @@ namespace BenchmarkDotNet.Loggers
10
10
internal class AsyncProcessOutputReader : IDisposable
11
11
{
12
12
private readonly Process process ;
13
- private readonly ConcurrentQueue < string > output , error ;
14
- private readonly bool logOutput , readStandardError ;
15
13
private readonly ILogger logger ;
14
+ private readonly bool logOutput , readStandardError ;
15
+
16
+ private static readonly TimeSpan FinishEventTimeout = TimeSpan . FromMilliseconds ( 500 ) ;
17
+ private readonly AutoResetEvent outputFinishEvent , errorFinishEvent ;
18
+ private readonly ConcurrentQueue < string > output , error ;
16
19
17
20
private long status ;
18
21
@@ -28,6 +31,8 @@ internal AsyncProcessOutputReader(Process process, bool logOutput = false, ILogg
28
31
this . process = process ;
29
32
output = new ConcurrentQueue < string > ( ) ;
30
33
error = new ConcurrentQueue < string > ( ) ;
34
+ outputFinishEvent = new AutoResetEvent ( false ) ;
35
+ errorFinishEvent = new AutoResetEvent ( false ) ;
31
36
status = ( long ) Status . Created ;
32
37
this . logOutput = logOutput ;
33
38
this . logger = logger ;
@@ -39,6 +44,9 @@ public void Dispose()
39
44
Interlocked . Exchange ( ref status , ( long ) Status . Disposed ) ;
40
45
41
46
Detach ( ) ;
47
+
48
+ outputFinishEvent . Dispose ( ) ;
49
+ errorFinishEvent . Dispose ( ) ;
42
50
}
43
51
44
52
internal void BeginRead ( )
@@ -72,6 +80,10 @@ internal void StopRead()
72
80
if ( Interlocked . CompareExchange ( ref status , ( long ) Status . Stopped , ( long ) Status . Started ) != ( long ) Status . Started )
73
81
throw new InvalidOperationException ( "Only a started reader can be stopped" ) ;
74
82
83
+ outputFinishEvent . WaitOne ( FinishEventTimeout ) ;
84
+ if ( readStandardError )
85
+ errorFinishEvent . WaitOne ( FinishEventTimeout ) ;
86
+
75
87
Detach ( ) ;
76
88
}
77
89
@@ -103,34 +115,44 @@ private void Detach()
103
115
104
116
private void ProcessOnOutputDataReceived ( object sender , DataReceivedEventArgs e )
105
117
{
106
- if ( ! string . IsNullOrEmpty ( e . Data ) )
118
+ if ( e . Data != null )
107
119
{
108
- output . Enqueue ( e . Data ) ;
109
-
110
- if ( logOutput )
120
+ if ( ! string . IsNullOrEmpty ( e . Data ) )
111
121
{
112
- lock ( this ) // #2125
122
+ output . Enqueue ( e . Data ) ;
123
+
124
+ if ( logOutput )
113
125
{
114
- logger . WriteLine ( e . Data ) ;
126
+ lock ( this ) // #2125
127
+ {
128
+ logger . WriteLine ( e . Data ) ;
129
+ }
115
130
}
116
131
}
117
132
}
133
+ else // 'e.Data == null' means EOF
134
+ outputFinishEvent . Set ( ) ;
118
135
}
119
136
120
137
private void ProcessOnErrorDataReceived ( object sender , DataReceivedEventArgs e )
121
138
{
122
- if ( ! string . IsNullOrEmpty ( e . Data ) )
139
+ if ( e . Data != null )
123
140
{
124
- error . Enqueue ( e . Data ) ;
125
-
126
- if ( logOutput )
141
+ if ( ! string . IsNullOrEmpty ( e . Data ) )
127
142
{
128
- lock ( this ) // #2125
143
+ error . Enqueue ( e . Data ) ;
144
+
145
+ if ( logOutput )
129
146
{
130
- logger . WriteLineError ( e . Data ) ;
147
+ lock ( this ) // #2125
148
+ {
149
+ logger . WriteLineError ( e . Data ) ;
150
+ }
131
151
}
132
152
}
133
153
}
154
+ else // 'e.Data == null' means EOF
155
+ errorFinishEvent . Set ( ) ;
134
156
}
135
157
136
158
private T ReturnIfStopped < T > ( Func < T > getter )
@@ -146,4 +168,4 @@ private enum Status : long
146
168
Disposed
147
169
}
148
170
}
149
- }
171
+ }
0 commit comments