diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvThread.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvThread.cs index 1591e57074..bc3e0139c5 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvThread.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvThread.cs @@ -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(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(); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/ListenerPrimary.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/ListenerPrimary.cs index 2b0fd8b039..7159d82c2c 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/ListenerPrimary.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/ListenerPrimary.cs @@ -18,7 +18,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal /// public class ListenerPrimary : Listener { + // The list of pipes that can be dispatched to (where we've confirmed the _pipeMessage) private readonly List _dispatchPipes = new List(); + // The list of pipes we've created but may not be part of _dispatchPipes + private readonly List _createdPipes = new List(); 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); }