Prevent ODE when ReadStart/Stop() is queued after disposal
This commit is contained in:
parent
5124adf450
commit
e9e0cf7325
|
|
@ -6,18 +6,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
private readonly long _maxSize;
|
private readonly long _maxSize;
|
||||||
private readonly IConnectionControl _connectionControl;
|
private readonly IConnectionControl _connectionControl;
|
||||||
private readonly KestrelThread _connectionThread;
|
|
||||||
|
|
||||||
private readonly object _lock = new object();
|
private readonly object _lock = new object();
|
||||||
|
|
||||||
private long _size;
|
private long _size;
|
||||||
private bool _connectionPaused;
|
private bool _connectionPaused;
|
||||||
|
|
||||||
public BufferSizeControl(long maxSize, IConnectionControl connectionControl, KestrelThread connectionThread)
|
public BufferSizeControl(long maxSize, IConnectionControl connectionControl)
|
||||||
{
|
{
|
||||||
_maxSize = maxSize;
|
_maxSize = maxSize;
|
||||||
_connectionControl = connectionControl;
|
_connectionControl = connectionControl;
|
||||||
_connectionThread = connectionThread;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long Size
|
private long Size
|
||||||
|
|
@ -50,9 +48,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
if (!_connectionPaused && Size >= _maxSize)
|
if (!_connectionPaused && Size >= _maxSize)
|
||||||
{
|
{
|
||||||
_connectionPaused = true;
|
_connectionPaused = true;
|
||||||
_connectionThread.Post(
|
_connectionControl.Pause();
|
||||||
(connectionControl) => ((IConnectionControl)connectionControl).Pause(),
|
|
||||||
_connectionControl);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,9 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
if (_connectionPaused && Size < _maxSize)
|
if (_connectionPaused && Size < _maxSize)
|
||||||
{
|
{
|
||||||
_connectionPaused = false;
|
_connectionPaused = false;
|
||||||
_connectionThread.Post(
|
_connectionControl.Resume();
|
||||||
(connectionControl) => ((IConnectionControl)connectionControl).Resume(),
|
|
||||||
_connectionControl);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
if (ServerOptions.Limits.MaxRequestBufferSize.HasValue)
|
if (ServerOptions.Limits.MaxRequestBufferSize.HasValue)
|
||||||
{
|
{
|
||||||
_bufferSizeControl = new BufferSizeControl(ServerOptions.Limits.MaxRequestBufferSize.Value, this, Thread);
|
_bufferSizeControl = new BufferSizeControl(ServerOptions.Limits.MaxRequestBufferSize.Value, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Input = new SocketInput(Thread.Memory, ThreadPool, _bufferSizeControl);
|
Input = new SocketInput(Thread.Memory, ThreadPool, _bufferSizeControl);
|
||||||
|
|
@ -285,22 +285,46 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
void IConnectionControl.Pause()
|
void IConnectionControl.Pause()
|
||||||
{
|
{
|
||||||
Log.ConnectionPause(ConnectionId);
|
Log.ConnectionPause(ConnectionId);
|
||||||
_socket.ReadStop();
|
|
||||||
|
// Even though this method is called on the event loop already,
|
||||||
|
// post anyway so the ReadStop() call doesn't get reordered
|
||||||
|
// relative to the ReadStart() call made in Resume().
|
||||||
|
Thread.Post(state => ((Connection)state).OnPausePosted(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IConnectionControl.Resume()
|
void IConnectionControl.Resume()
|
||||||
{
|
{
|
||||||
Log.ConnectionResume(ConnectionId);
|
Log.ConnectionResume(ConnectionId);
|
||||||
try
|
|
||||||
|
// This is called from the consuming thread.
|
||||||
|
Thread.Post(state => ((Connection)state).OnResumePosted(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPausePosted()
|
||||||
|
{
|
||||||
|
// It's possible that uv_close was called between the call to Thread.Post() and now.
|
||||||
|
if (!_socket.IsClosed)
|
||||||
{
|
{
|
||||||
_socket.ReadStart(_allocCallback, _readCallback, this);
|
_socket.ReadStop();
|
||||||
}
|
}
|
||||||
catch (UvException)
|
}
|
||||||
|
|
||||||
|
private void OnResumePosted()
|
||||||
|
{
|
||||||
|
// It's possible that uv_close was called even before the call to Resume().
|
||||||
|
if (!_socket.IsClosed)
|
||||||
{
|
{
|
||||||
// ReadStart() can throw a UvException in some cases (e.g. socket is no longer connected).
|
try
|
||||||
// This should be treated the same as OnRead() seeing a "normalDone" condition.
|
{
|
||||||
Log.ConnectionReadFin(ConnectionId);
|
_socket.ReadStart(_allocCallback, _readCallback, this);
|
||||||
Input.IncomingComplete(0, null);
|
}
|
||||||
|
catch (UvException)
|
||||||
|
{
|
||||||
|
// ReadStart() can throw a UvException in some cases (e.g. socket is no longer connected).
|
||||||
|
// This should be treated the same as OnRead() seeing a "normalDone" condition.
|
||||||
|
Log.ConnectionReadFin(ConnectionId);
|
||||||
|
Input.IncomingComplete(0, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue