Don't rely on the finalizer to return blocks referenced by SocketInput
This commit is contained in:
parent
87bd60746b
commit
9c31907bac
|
|
@ -48,10 +48,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Filter
|
|||
{
|
||||
if (copyAsyncTask.IsFaulted)
|
||||
{
|
||||
SocketInput.AbortAwaiting();
|
||||
_log.LogError(0, copyAsyncTask.Exception, "FilteredStreamAdapter.CopyToAsync");
|
||||
}
|
||||
else if (copyAsyncTask.IsCanceled)
|
||||
{
|
||||
SocketInput.AbortAwaiting();
|
||||
_log.LogError("FilteredStreamAdapter.CopyToAsync canceled.");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
}
|
||||
}
|
||||
|
||||
public void OnSocketClosed()
|
||||
{
|
||||
_rawSocketInput.Dispose();
|
||||
|
||||
// If a connection filter was applied there will be two SocketInputs.
|
||||
// If a connection filter failed, SocketInput will be null.
|
||||
if (SocketInput != null && SocketInput != _rawSocketInput)
|
||||
{
|
||||
SocketInput.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyConnectionFilter()
|
||||
{
|
||||
if (_filterContext.Connection != _libuvStream)
|
||||
|
|
|
|||
|
|
@ -334,7 +334,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
try
|
||||
{
|
||||
ConnectionControl.End(ProduceEndType.SocketDisconnect);
|
||||
SocketInput.AbortAwaiting();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -145,14 +145,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
// If _requestAborted is set, the connection has already been closed.
|
||||
if (Volatile.Read(ref _requestAborted) == 0)
|
||||
{
|
||||
// Inform client no more data will ever arrive
|
||||
ConnectionControl.End(ProduceEndType.SocketShutdownSend);
|
||||
try
|
||||
{
|
||||
// Inform client no more data will ever arrive
|
||||
ConnectionControl.End(ProduceEndType.SocketShutdownSend);
|
||||
|
||||
// Wait for client to either disconnect or send unexpected data
|
||||
await SocketInput;
|
||||
|
||||
// Dispose socket
|
||||
ConnectionControl.End(ProduceEndType.SocketDisconnect);
|
||||
// Wait for client to either disconnect or send unexpected data
|
||||
await SocketInput;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Ensure we *always* disconnect the socket.
|
||||
// Dispose socket
|
||||
ConnectionControl.End(ProduceEndType.SocketDisconnect);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||
{
|
||||
public class SocketInput : ICriticalNotifyCompletion
|
||||
public class SocketInput : ICriticalNotifyCompletion, IDisposable
|
||||
{
|
||||
private static readonly Action _awaitableIsCompleted = () => { };
|
||||
private static readonly Action _awaitableIsNotCompleted = () => { };
|
||||
|
|
@ -246,5 +246,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
throw new IOException(error.Message, error);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
AbortAwaiting();
|
||||
|
||||
// Return all blocks
|
||||
var block = _head;
|
||||
while (block != null)
|
||||
{
|
||||
var returnBlock = block;
|
||||
block = block.Next;
|
||||
|
||||
returnBlock.Pool.Return(returnBlock);
|
||||
}
|
||||
|
||||
_head = null;
|
||||
_tail = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -614,17 +614,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
{
|
||||
if (SocketDisconnect == false || Self._socket.IsClosed)
|
||||
{
|
||||
CompleteOnUvThread();
|
||||
CompleteWithContextLock();
|
||||
return;
|
||||
}
|
||||
|
||||
Self._socket.Dispose();
|
||||
Self._connection.OnSocketClosed();
|
||||
Self.ReturnAllBlocks();
|
||||
Self._log.ConnectionStop(Self._connectionId);
|
||||
CompleteOnUvThread();
|
||||
CompleteWithContextLock();
|
||||
}
|
||||
|
||||
public void CompleteOnUvThread()
|
||||
public void CompleteWithContextLock()
|
||||
{
|
||||
if (Monitor.TryEnter(Self._contextLock))
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue