Fix deadlocks in startup and shutdown
This commit is contained in:
parent
ed4a27a827
commit
6036f27f52
|
|
@ -287,7 +287,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
||||||
var connectionHandler = new ConnectionHandler<TContext>(ipv4ListenOptions, serviceContext, application);
|
var connectionHandler = new ConnectionHandler<TContext>(ipv4ListenOptions, serviceContext, application);
|
||||||
var transport = _transportFactory.Create(ipv4ListenOptions, connectionHandler);
|
var transport = _transportFactory.Create(ipv4ListenOptions, connectionHandler);
|
||||||
_transports.Add(transport);
|
_transports.Add(transport);
|
||||||
await transport.BindAsync();
|
await transport.BindAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (AddressInUseException ex)
|
catch (AddressInUseException ex)
|
||||||
{
|
{
|
||||||
|
|
@ -306,7 +306,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
||||||
var connectionHandler = new ConnectionHandler<TContext>(ipv6ListenOptions, serviceContext, application);
|
var connectionHandler = new ConnectionHandler<TContext>(ipv6ListenOptions, serviceContext, application);
|
||||||
var transport = _transportFactory.Create(ipv6ListenOptions, connectionHandler);
|
var transport = _transportFactory.Create(ipv6ListenOptions, connectionHandler);
|
||||||
_transports.Add(transport);
|
_transports.Add(transport);
|
||||||
await transport.BindAsync();
|
await transport.BindAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (AddressInUseException ex)
|
catch (AddressInUseException ex)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
private readonly UvStreamHandle _socket;
|
private readonly UvStreamHandle _socket;
|
||||||
private IConnectionContext _connectionContext;
|
private IConnectionContext _connectionContext;
|
||||||
|
|
||||||
private TaskCompletionSource<object> _socketClosedTcs = new TaskCompletionSource<object>();
|
private TaskCompletionSource<object> _socketClosedTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
private WritableBuffer? _currentWritableBuffer;
|
private WritableBuffer? _currentWritableBuffer;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
|
|
||||||
private async Task<bool> WalkConnectionsAsync(Action<LibuvConnectionManager, TaskCompletionSource<object>> action, TimeSpan timeout)
|
private async Task<bool> WalkConnectionsAsync(Action<LibuvConnectionManager, TaskCompletionSource<object>> action, TimeSpan timeout)
|
||||||
{
|
{
|
||||||
var tcs = new TaskCompletionSource<object>();
|
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
_thread.Post(state => action(state, tcs), this);
|
_thread.Post(state => action(state, tcs), this);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
private readonly LibuvTransport _transport;
|
private readonly LibuvTransport _transport;
|
||||||
private readonly IApplicationLifetime _appLifetime;
|
private readonly IApplicationLifetime _appLifetime;
|
||||||
private readonly Thread _thread;
|
private readonly Thread _thread;
|
||||||
private readonly TaskCompletionSource<object> _threadTcs = new TaskCompletionSource<object>();
|
private readonly TaskCompletionSource<object> _threadTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
private readonly UvLoopHandle _loop;
|
private readonly UvLoopHandle _loop;
|
||||||
private readonly UvAsyncHandle _post;
|
private readonly UvAsyncHandle _post;
|
||||||
private Queue<Work> _workAdding = new Queue<Work>(1024);
|
private Queue<Work> _workAdding = new Queue<Work>(1024);
|
||||||
|
|
@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
|
|
||||||
public Task StartAsync()
|
public Task StartAsync()
|
||||||
{
|
{
|
||||||
var tcs = new TaskCompletionSource<int>();
|
var tcs = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
_thread.Start(tcs);
|
_thread.Start(tcs);
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
|
|
||||||
public Task PostAsync<T>(Action<T> callback, T state)
|
public Task PostAsync<T>(Action<T> callback, T state)
|
||||||
{
|
{
|
||||||
var tcs = new TaskCompletionSource<object>();
|
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
lock (_workSync)
|
lock (_workSync)
|
||||||
{
|
{
|
||||||
_workAdding.Enqueue(new Work
|
_workAdding.Enqueue(new Work
|
||||||
|
|
@ -332,36 +332,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
work.CallbackAdapter(work.Callback, work.State);
|
work.CallbackAdapter(work.Callback, work.State);
|
||||||
if (work.Completion != null)
|
work.Completion?.TrySetResult(null);
|
||||||
{
|
|
||||||
ThreadPool.QueueUserWorkItem(o =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
((TaskCompletionSource<object>)o).SetResult(null);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_log.LogError(0, e, $"{nameof(LibuvThread)}.{nameof(DoPostWork)}");
|
|
||||||
}
|
|
||||||
}, work.Completion);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (work.Completion != null)
|
if (work.Completion != null)
|
||||||
{
|
{
|
||||||
ThreadPool.QueueUserWorkItem(o =>
|
work.Completion.TrySetException(ex);
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
((TaskCompletionSource<object>)o).TrySetException(ex);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_log.LogError(0, e, $"{nameof(LibuvThread)}.{nameof(DoPostWork)}");
|
|
||||||
}
|
|
||||||
}, work.Completion);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -31,25 +31,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
EndPointInformation = endPointInformation;
|
EndPointInformation = endPointInformation;
|
||||||
Thread = thread;
|
Thread = thread;
|
||||||
|
|
||||||
var tcs = new TaskCompletionSource<int>(this);
|
return Thread.PostAsync(listener =>
|
||||||
|
|
||||||
Thread.Post(state =>
|
|
||||||
{
|
{
|
||||||
var tcs2 = state;
|
listener.ListenSocket = listener.CreateListenSocket();
|
||||||
try
|
listener.ListenSocket.Listen(LibuvConstants.ListenBacklog, ConnectionCallback, listener);
|
||||||
{
|
}, this);
|
||||||
var listener = ((Listener) tcs2.Task.AsyncState);
|
|
||||||
listener.ListenSocket = listener.CreateListenSocket();
|
|
||||||
ListenSocket.Listen(LibuvConstants.ListenBacklog, ConnectionCallback, this);
|
|
||||||
tcs2.SetResult(0);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
tcs2.SetException(ex);
|
|
||||||
}
|
|
||||||
}, tcs);
|
|
||||||
|
|
||||||
return tcs.Task;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -157,9 +143,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
// the exception that stopped the event loop will never be surfaced.
|
// the exception that stopped the event loop will never be surfaced.
|
||||||
if (Thread.FatalError == null && ListenSocket != null)
|
if (Thread.FatalError == null && ListenSocket != null)
|
||||||
{
|
{
|
||||||
await Thread.PostAsync(state =>
|
await Thread.PostAsync(listener =>
|
||||||
{
|
{
|
||||||
var listener = (Listener)state;
|
|
||||||
listener.ListenSocket.Dispose();
|
listener.ListenSocket.Dispose();
|
||||||
|
|
||||||
listener._closed = true;
|
listener._closed = true;
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
|
|
||||||
await StartAsync(endPointInformation, thread).ConfigureAwait(false);
|
await StartAsync(endPointInformation, thread).ConfigureAwait(false);
|
||||||
|
|
||||||
await Thread.PostAsync(state => ((ListenerPrimary)state).PostCallback(),
|
await Thread.PostAsync(listener => listener.PostCallback(), this).ConfigureAwait(false);
|
||||||
this).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PostCallback()
|
private void PostCallback()
|
||||||
|
|
@ -175,9 +174,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
|
|
||||||
if (Thread.FatalError == null && ListenPipe != null)
|
if (Thread.FatalError == null && ListenPipe != null)
|
||||||
{
|
{
|
||||||
await Thread.PostAsync(state =>
|
await Thread.PostAsync(listener =>
|
||||||
{
|
{
|
||||||
var listener = (ListenerPrimary)state;
|
|
||||||
listener.ListenPipe.Dispose();
|
listener.ListenPipe.Dispose();
|
||||||
|
|
||||||
foreach (var dispatchPipe in listener._dispatchPipes)
|
foreach (var dispatchPipe in listener._dispatchPipes)
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
Thread = thread;
|
Thread = thread;
|
||||||
DispatchPipe = new UvPipeHandle(Log);
|
DispatchPipe = new UvPipeHandle(Log);
|
||||||
|
|
||||||
var tcs = new TaskCompletionSource<int>(this);
|
var tcs = new TaskCompletionSource<int>(this, TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
Thread.Post(StartCallback, tcs);
|
Thread.Post(StartCallback, tcs);
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
@ -185,9 +185,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
// the exception that stopped the event loop will never be surfaced.
|
// the exception that stopped the event loop will never be surfaced.
|
||||||
if (Thread.FatalError == null)
|
if (Thread.FatalError == null)
|
||||||
{
|
{
|
||||||
await Thread.PostAsync(state =>
|
await Thread.PostAsync(listener =>
|
||||||
{
|
{
|
||||||
var listener = (ListenerSecondary)state;
|
|
||||||
listener.DispatchPipe.Dispose();
|
listener.DispatchPipe.Dispose();
|
||||||
listener.FreeBuffer();
|
listener.FreeBuffer();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue