Fix EBUSY errors on uv_loop_close (#1798)

* Fix race where ListenerPrimary is disposed before secondary listeners spin up
- Since we only add listeners to dispatch pipes after receiving the "ack" message
it's possible to have pipes that were created but not acked yet. We might miss
disposal of those pipes if they were never added to the list of _dispatchPipes.

#1761
This commit is contained in:
David Fowler 2017-05-01 14:55:32 -07:00 committed by GitHub
parent 4dd4a573e6
commit 35b5d92652
2 changed files with 18 additions and 2 deletions

View File

@ -264,6 +264,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
_post.Reference();
_post.Dispose();
// We need this walk because we call ReadStop on on accepted connections when there's back pressure
// Calling ReadStop makes the handle as in-active which means the loop can
// end while there's still valid handles around. This makes loop.Dispose throw
// with an EBUSY. To avoid that, we walk all of the handles and dispose them.
Walk(ptr =>
{
var handle = UvMemory.FromIntPtr<UvHandle>(ptr);
// handle can be null because UvMemory.FromIntPtr looks up a weak reference
handle?.Dispose();
});
// Ensure the Dispose operations complete in the event loop.
_loop.Run();

View File

@ -18,7 +18,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
/// </summary>
public class ListenerPrimary : Listener
{
// The list of pipes that can be dispatched to (where we've confirmed the _pipeMessage)
private readonly List<UvPipeHandle> _dispatchPipes = new List<UvPipeHandle>();
// The list of pipes we've created but may not be part of _dispatchPipes
private readonly List<UvPipeHandle> _createdPipes = new List<UvPipeHandle>();
private int _dispatchIndex;
private string _pipeName;
private byte[] _pipeMessage;
@ -78,6 +81,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
}
var dispatchPipe = new UvPipeHandle(Log);
// Add to the list of created pipes for disposal tracking
_createdPipes.Add(dispatchPipe);
try
{
@ -191,9 +196,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
listener.ListenPipe.Dispose();
foreach (var dispatchPipe in listener._dispatchPipes)
foreach (var pipe in listener._createdPipes)
{
dispatchPipe.Dispose();
pipe.Dispose();
}
}, this).ConfigureAwait(false);
}