@@ -25,6 +25,8 @@ public async Task PassthroughIfAllFlushesAreAwaited()
25
25
} ;
26
26
27
27
var mockPipeWriter = new MockPipeWriter ( pipeWriterFlushTcsArray ) ;
28
+
29
+ // No need to pass in a real sync object since all the calls in this test are passthrough.
28
30
var concurrentPipeWriter = new ConcurrentPipeWriter ( mockPipeWriter , diagnosticPool , new object ( ) ) ;
29
31
30
32
var memory = concurrentPipeWriter . GetMemory ( ) ;
@@ -71,24 +73,31 @@ public async Task QueuesIfFlushIsNotAwaited()
71
73
new TaskCompletionSource < FlushResult > ( TaskCreationOptions . RunContinuationsAsynchronously ) ,
72
74
} ;
73
75
76
+ var sync = new object ( ) ;
74
77
var mockPipeWriter = new MockPipeWriter ( pipeWriterFlushTcsArray ) ;
75
- var concurrentPipeWriter = new ConcurrentPipeWriter ( mockPipeWriter , diagnosticPool , new object ( ) ) ;
78
+ var concurrentPipeWriter = new ConcurrentPipeWriter ( mockPipeWriter , diagnosticPool , sync ) ;
79
+ var flushTask0 = default ( ValueTask < FlushResult > ) ;
80
+ var flushTask1 = default ( ValueTask < FlushResult > ) ;
81
+ var completeTask = default ( ValueTask ) ;
76
82
77
- var memory = concurrentPipeWriter . GetMemory ( ) ;
78
- Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
83
+ lock ( sync )
84
+ {
85
+ var memory = concurrentPipeWriter . GetMemory ( ) ;
86
+ Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
79
87
80
- concurrentPipeWriter . Advance ( memory . Length ) ;
81
- Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
88
+ concurrentPipeWriter . Advance ( memory . Length ) ;
89
+ Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
82
90
83
- var flushTask0 = concurrentPipeWriter . FlushAsync ( ) ;
84
- Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
91
+ flushTask0 = concurrentPipeWriter . FlushAsync ( ) ;
92
+ Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
85
93
86
- Assert . False ( flushTask0 . IsCompleted ) ;
87
-
88
- // Since the flush was not awaited, the following API calls are queued.
89
- memory = concurrentPipeWriter . GetMemory ( ) ;
90
- concurrentPipeWriter . Advance ( memory . Length ) ;
91
- var flushTask1 = concurrentPipeWriter . FlushAsync ( ) ;
94
+ Assert . False ( flushTask0 . IsCompleted ) ;
95
+
96
+ // Since the flush was not awaited, the following API calls are queued.
97
+ memory = concurrentPipeWriter . GetMemory ( ) ;
98
+ concurrentPipeWriter . Advance ( memory . Length ) ;
99
+ flushTask1 = concurrentPipeWriter . FlushAsync ( ) ;
100
+ }
92
101
93
102
Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
94
103
Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
@@ -99,11 +108,15 @@ public async Task QueuesIfFlushIsNotAwaited()
99
108
100
109
mockPipeWriter . FlushTcs = new TaskCompletionSource < object > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
101
110
pipeWriterFlushTcsArray [ 0 ] . SetResult ( default ) ;
111
+
102
112
await mockPipeWriter . FlushTcs . Task . DefaultTimeout ( ) ;
103
113
104
- // Since the flush was not awaited, the following API calls are queued.
105
- memory = concurrentPipeWriter . GetMemory ( ) ;
106
- concurrentPipeWriter . Advance ( memory . Length ) ;
114
+ lock ( sync )
115
+ {
116
+ // Since the flush was not awaited, the following API calls are queued.
117
+ var memory = concurrentPipeWriter . GetMemory ( ) ;
118
+ concurrentPipeWriter . Advance ( memory . Length ) ;
119
+ }
107
120
108
121
// We do not need to flush the final bytes, since the incomplete flush will pick it up.
109
122
Assert . Equal ( 2 , mockPipeWriter . GetMemoryCallCount ) ;
@@ -115,6 +128,7 @@ public async Task QueuesIfFlushIsNotAwaited()
115
128
116
129
mockPipeWriter . FlushTcs = new TaskCompletionSource < object > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
117
130
pipeWriterFlushTcsArray [ 1 ] . SetResult ( default ) ;
131
+
118
132
await mockPipeWriter . FlushTcs . Task . DefaultTimeout ( ) ;
119
133
120
134
// Even though we only called flush on the ConcurrentPipeWriter twice, the inner PipeWriter was flushed three times.
@@ -126,7 +140,12 @@ public async Task QueuesIfFlushIsNotAwaited()
126
140
Assert . False ( flushTask1 . IsCompleted ) ;
127
141
128
142
var completeEx = new Exception ( ) ;
129
- await concurrentPipeWriter . CompleteAsync ( completeEx ) ;
143
+ lock ( sync )
144
+ {
145
+ completeTask = concurrentPipeWriter . CompleteAsync ( completeEx ) ;
146
+ }
147
+
148
+ await completeTask . DefaultTimeout ( ) ;
130
149
131
150
// Complete isn't called on the inner PipeWriter until the inner flushes have completed.
132
151
Assert . Null ( mockPipeWriter . CompleteException ) ;
@@ -151,21 +170,29 @@ public async Task KeepsQueueIfInnerFlushFinishesBetweenGetMemoryAndAdvance()
151
170
new TaskCompletionSource < FlushResult > ( TaskCreationOptions . RunContinuationsAsynchronously ) ,
152
171
} ;
153
172
173
+ var sync = new object ( ) ;
154
174
var mockPipeWriter = new MockPipeWriter ( pipeWriterFlushTcsArray ) ;
155
- var concurrentPipeWriter = new ConcurrentPipeWriter ( mockPipeWriter , diagnosticPool , new object ( ) ) ;
175
+ var concurrentPipeWriter = new ConcurrentPipeWriter ( mockPipeWriter , diagnosticPool , sync ) ;
176
+ var memory = default ( Memory < byte > ) ;
177
+ var flushTask0 = default ( ValueTask < FlushResult > ) ;
178
+ var flushTask1 = default ( ValueTask < FlushResult > ) ;
179
+ var completeTask = default ( ValueTask ) ;
156
180
157
- var memory = concurrentPipeWriter . GetMemory ( ) ;
158
- Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
181
+ lock ( sync )
182
+ {
183
+ memory = concurrentPipeWriter . GetMemory ( ) ;
184
+ Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
159
185
160
- concurrentPipeWriter . Advance ( memory . Length ) ;
161
- Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
186
+ concurrentPipeWriter . Advance ( memory . Length ) ;
187
+ Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
162
188
163
- var flushTask0 = concurrentPipeWriter . FlushAsync ( ) ;
164
- Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
165
- Assert . False ( flushTask0 . IsCompleted ) ;
189
+ flushTask0 = concurrentPipeWriter . FlushAsync ( ) ;
190
+ Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
191
+ Assert . False ( flushTask0 . IsCompleted ) ;
166
192
167
- // Only GetMemory() is called but not Advance() is not called yet when the first inner flush complets.
168
- memory = concurrentPipeWriter . GetMemory ( ) ;
193
+ // Only GetMemory() is called but not Advance() is not called yet when the first inner flush complets.
194
+ memory = concurrentPipeWriter . GetMemory ( ) ;
195
+ }
169
196
170
197
// If the inner flush completes between a call to GetMemory() and Advance(), the outer
171
198
// flush completes, and the next flush will pick up the buffered data.
@@ -177,11 +204,14 @@ public async Task KeepsQueueIfInnerFlushFinishesBetweenGetMemoryAndAdvance()
177
204
Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
178
205
Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
179
206
180
- concurrentPipeWriter . Advance ( memory . Length ) ;
181
- memory = concurrentPipeWriter . GetMemory ( ) ;
182
- concurrentPipeWriter . Advance ( memory . Length ) ;
207
+ lock ( sync )
208
+ {
209
+ concurrentPipeWriter . Advance ( memory . Length ) ;
210
+ memory = concurrentPipeWriter . GetMemory ( ) ;
211
+ concurrentPipeWriter . Advance ( memory . Length ) ;
183
212
184
- var flushTask1 = concurrentPipeWriter . FlushAsync ( ) ;
213
+ flushTask1 = concurrentPipeWriter . FlushAsync ( ) ;
214
+ }
185
215
186
216
// Now that we flushed the ConcurrentPipeWriter again, the GetMemory() and Advance() calls are replayed.
187
217
// Make sure that MockPipeWriter.SlabMemoryPoolBlockSize matches SlabMemoryPool._blockSize or else
@@ -201,7 +231,14 @@ public async Task KeepsQueueIfInnerFlushFinishesBetweenGetMemoryAndAdvance()
201
231
Assert . Equal ( 2 , mockPipeWriter . FlushCallCount ) ;
202
232
203
233
var completeEx = new Exception ( ) ;
204
- await concurrentPipeWriter . CompleteAsync ( completeEx ) ;
234
+
235
+ lock ( sync )
236
+ {
237
+ completeTask = concurrentPipeWriter . CompleteAsync ( completeEx ) ;
238
+ }
239
+
240
+ await completeTask . DefaultTimeout ( ) ;
241
+
205
242
Assert . Same ( completeEx , mockPipeWriter . CompleteException ) ;
206
243
}
207
244
}
@@ -217,21 +254,28 @@ public async Task CompleteFlushesQueuedBytes()
217
254
new TaskCompletionSource < FlushResult > ( TaskCreationOptions . RunContinuationsAsynchronously ) ,
218
255
} ;
219
256
257
+ var sync = new object ( ) ;
220
258
var mockPipeWriter = new MockPipeWriter ( pipeWriterFlushTcsArray ) ;
221
- var concurrentPipeWriter = new ConcurrentPipeWriter ( mockPipeWriter , diagnosticPool , new object ( ) ) ;
259
+ var concurrentPipeWriter = new ConcurrentPipeWriter ( mockPipeWriter , diagnosticPool , sync ) ;
260
+ var memory = default ( Memory < byte > ) ;
261
+ var flushTask0 = default ( ValueTask < FlushResult > ) ;
262
+ var completeTask = default ( ValueTask ) ;
222
263
223
- var memory = concurrentPipeWriter . GetMemory ( ) ;
224
- Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
264
+ lock ( sync )
265
+ {
266
+ memory = concurrentPipeWriter . GetMemory ( ) ;
267
+ Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
225
268
226
- concurrentPipeWriter . Advance ( memory . Length ) ;
227
- Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
269
+ concurrentPipeWriter . Advance ( memory . Length ) ;
270
+ Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
228
271
229
- var flushTask0 = concurrentPipeWriter . FlushAsync ( ) ;
230
- Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
231
- Assert . False ( flushTask0 . IsCompleted ) ;
272
+ flushTask0 = concurrentPipeWriter . FlushAsync ( ) ;
273
+ Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
274
+ Assert . False ( flushTask0 . IsCompleted ) ;
232
275
233
- // Only GetMemory() is called but not Advance() is not called yet when the first inner flush completes.
234
- memory = concurrentPipeWriter . GetMemory ( ) ;
276
+ // Only GetMemory() is called but not Advance() is not called yet when the first inner flush completes.
277
+ memory = concurrentPipeWriter . GetMemory ( ) ;
278
+ }
235
279
236
280
// If the inner flush completes between a call to GetMemory() and Advance(), the outer
237
281
// flush completes, and the next flush will pick up the buffered data.
@@ -243,13 +287,19 @@ public async Task CompleteFlushesQueuedBytes()
243
287
Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
244
288
Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
245
289
246
- concurrentPipeWriter . Advance ( memory . Length ) ;
247
- memory = concurrentPipeWriter . GetMemory ( ) ;
248
- concurrentPipeWriter . Advance ( memory . Length ) ;
249
-
250
- // Complete the ConcurrentPipeWriter without flushing any of the queued data.
251
290
var completeEx = new Exception ( ) ;
252
- await concurrentPipeWriter . CompleteAsync ( completeEx ) ;
291
+
292
+ lock ( sync )
293
+ {
294
+ concurrentPipeWriter . Advance ( memory . Length ) ;
295
+ memory = concurrentPipeWriter . GetMemory ( ) ;
296
+ concurrentPipeWriter . Advance ( memory . Length ) ;
297
+
298
+ // Complete the ConcurrentPipeWriter without flushing any of the queued data.
299
+ completeTask = concurrentPipeWriter . CompleteAsync ( completeEx ) ;
300
+ }
301
+
302
+ await completeTask . DefaultTimeout ( ) ;
253
303
254
304
// Now that we completed the ConcurrentPipeWriter, the GetMemory() and Advance() calls are replayed.
255
305
// Make sure that MockPipeWriter.SlabMemoryPoolBlockSize matches SlabMemoryPool._blockSize or else
@@ -272,45 +322,58 @@ public async Task CancelPendingFlushInterruptsFlushLoop()
272
322
new TaskCompletionSource < FlushResult > ( TaskCreationOptions . RunContinuationsAsynchronously ) ,
273
323
} ;
274
324
325
+ var sync = new object ( ) ;
275
326
var mockPipeWriter = new MockPipeWriter ( pipeWriterFlushTcsArray ) ;
276
- var concurrentPipeWriter = new ConcurrentPipeWriter ( mockPipeWriter , diagnosticPool , new object ( ) ) ;
327
+ var concurrentPipeWriter = new ConcurrentPipeWriter ( mockPipeWriter , diagnosticPool , sync ) ;
328
+ var flushTask0 = default ( ValueTask < FlushResult > ) ;
329
+ var flushTask1 = default ( ValueTask < FlushResult > ) ;
330
+ var flushTask2 = default ( ValueTask < FlushResult > ) ;
331
+ var completeTask = default ( ValueTask ) ;
277
332
278
- var memory = concurrentPipeWriter . GetMemory ( ) ;
279
- Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
333
+ lock ( sync )
334
+ {
335
+ var memory = concurrentPipeWriter . GetMemory ( ) ;
336
+ Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
280
337
281
- concurrentPipeWriter . Advance ( memory . Length ) ;
282
- Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
338
+ concurrentPipeWriter . Advance ( memory . Length ) ;
339
+ Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
283
340
284
- var flushTask0 = concurrentPipeWriter . FlushAsync ( ) ;
285
- Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
341
+ flushTask0 = concurrentPipeWriter . FlushAsync ( ) ;
342
+ Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
286
343
287
- Assert . False ( flushTask0 . IsCompleted ) ;
288
-
289
- // Since the flush was not awaited, the following API calls are queued.
290
- memory = concurrentPipeWriter . GetMemory ( ) ;
291
- concurrentPipeWriter . Advance ( memory . Length ) ;
292
- var flushTask1 = concurrentPipeWriter . FlushAsync ( ) ;
344
+ Assert . False ( flushTask0 . IsCompleted ) ;
293
345
294
- Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
295
- Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
296
- Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
346
+ // Since the flush was not awaited, the following API calls are queued.
347
+ memory = concurrentPipeWriter . GetMemory ( ) ;
348
+ concurrentPipeWriter . Advance ( memory . Length ) ;
349
+ flushTask1 = concurrentPipeWriter . FlushAsync ( ) ;
297
350
298
- Assert . False ( flushTask0 . IsCompleted ) ;
299
- Assert . False ( flushTask1 . IsCompleted ) ;
351
+ Assert . Equal ( 1 , mockPipeWriter . GetMemoryCallCount ) ;
352
+ Assert . Equal ( 1 , mockPipeWriter . AdvanceCallCount ) ;
353
+ Assert . Equal ( 1 , mockPipeWriter . FlushCallCount ) ;
300
354
301
- // CancelPendingFlush() does not get queued.
302
- concurrentPipeWriter . CancelPendingFlush ( ) ;
303
- Assert . Equal ( 1 , mockPipeWriter . CancelPendingFlushCallCount ) ;
355
+ Assert . False ( flushTask0 . IsCompleted ) ;
356
+ Assert . False ( flushTask1 . IsCompleted ) ;
357
+
358
+ // CancelPendingFlush() does not get queued.
359
+ concurrentPipeWriter . CancelPendingFlush ( ) ;
360
+ Assert . Equal ( 1 , mockPipeWriter . CancelPendingFlushCallCount ) ;
361
+ }
304
362
305
363
pipeWriterFlushTcsArray [ 0 ] . SetResult ( new FlushResult ( isCanceled : true , isCompleted : false ) ) ;
306
364
307
365
Assert . True ( ( await flushTask0 . DefaultTimeout ( ) ) . IsCanceled ) ;
308
366
Assert . True ( ( await flushTask1 . DefaultTimeout ( ) ) . IsCanceled ) ;
309
367
310
- var flushTask2 = concurrentPipeWriter . FlushAsync ( ) ;
368
+ lock ( sync )
369
+ {
370
+ flushTask2 = concurrentPipeWriter . FlushAsync ( ) ;
371
+ }
372
+
311
373
Assert . False ( flushTask2 . IsCompleted ) ;
312
374
313
375
pipeWriterFlushTcsArray [ 1 ] . SetResult ( default ) ;
376
+
314
377
await flushTask2 . DefaultTimeout ( ) ;
315
378
316
379
// We do not need to flush the final bytes, since the incomplete flush will pick it up.
@@ -319,7 +382,14 @@ public async Task CancelPendingFlushInterruptsFlushLoop()
319
382
Assert . Equal ( 2 , mockPipeWriter . FlushCallCount ) ;
320
383
321
384
var completeEx = new Exception ( ) ;
322
- await concurrentPipeWriter . CompleteAsync ( completeEx ) ;
385
+
386
+ lock ( sync )
387
+ {
388
+ completeTask = concurrentPipeWriter . CompleteAsync ( completeEx ) ;
389
+ }
390
+
391
+ await completeTask . DefaultTimeout ( ) ;
392
+
323
393
Assert . Same ( completeEx , mockPipeWriter . CompleteException ) ;
324
394
}
325
395
}
0 commit comments