Prevent possible deadlocks when using MockLibuv.OnPostTask

This commit is contained in:
Stephen Halter 2016-08-29 12:14:19 -07:00
parent b6a177ef0b
commit 4587a0fc95
1 changed files with 17 additions and 4 deletions

View File

@ -12,8 +12,10 @@ namespace Microsoft.AspNetCore.Server.KestrelTests.TestHelpers
{ {
private UvAsyncHandle _postHandle; private UvAsyncHandle _postHandle;
private uv_async_cb _onPost; private uv_async_cb _onPost;
private TaskCompletionSource<object> _onPostTcs;
private object _postLock = new object(); private readonly object _postLock = new object();
private TaskCompletionSource<object> _onPostTcs = new TaskCompletionSource<object>();
private bool _completedOnPostTcs;
private bool _stopLoop; private bool _stopLoop;
private readonly ManualResetEventSlim _loopWh = new ManualResetEventSlim(); private readonly ManualResetEventSlim _loopWh = new ManualResetEventSlim();
@ -37,9 +39,10 @@ namespace Microsoft.AspNetCore.Server.KestrelTests.TestHelpers
{ {
lock (_postLock) lock (_postLock)
{ {
if (_onPostTcs == null || _onPostTcs.Task.IsCompleted) if (_completedOnPostTcs)
{ {
_onPostTcs = new TaskCompletionSource<object>(); _onPostTcs = new TaskCompletionSource<object>();
_completedOnPostTcs = false;
} }
PostCount++; PostCount++;
@ -64,13 +67,23 @@ namespace Microsoft.AspNetCore.Server.KestrelTests.TestHelpers
{ {
_loopWh.Wait(); _loopWh.Wait();
KestrelThreadBlocker.Wait(); KestrelThreadBlocker.Wait();
TaskCompletionSource<object> onPostTcs;
lock (_postLock) lock (_postLock)
{ {
_loopWh.Reset(); _loopWh.Reset();
_onPost(_postHandle.InternalGetHandle()); _onPost(_postHandle.InternalGetHandle());
_onPostTcs.TrySetResult(null);
// Ensure any subsequent calls to uv_async_send
// create a new _onPostTcs to be completed.
onPostTcs = _onPostTcs;
_completedOnPostTcs = true;
} }
// Calling TrySetResult outside the lock to avoid deadlock
// when the code attempts to call uv_async_send after awaiting
// OnPostTask.
onPostTcs.TrySetResult(null);
} }
return 0; return 0;