Lock around Connection.End to make it thread-safe
This commit is contained in:
parent
4f0480a4d0
commit
32c4f314b6
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNet.Server.Kestrel.Networking;
|
using Microsoft.AspNet.Server.Kestrel.Networking;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Server.Kestrel.Http
|
namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
{
|
{
|
||||||
|
|
@ -16,8 +15,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
private static readonly Action<UvStreamHandle, int, Exception, object> _readCallback = ReadCallback;
|
private static readonly Action<UvStreamHandle, int, Exception, object> _readCallback = ReadCallback;
|
||||||
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback = AllocCallback;
|
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback = AllocCallback;
|
||||||
|
|
||||||
private int _connectionState;
|
|
||||||
|
|
||||||
private static Libuv.uv_buf_t AllocCallback(UvStreamHandle handle, int suggestedSize, object state)
|
private static Libuv.uv_buf_t AllocCallback(UvStreamHandle handle, int suggestedSize, object state)
|
||||||
{
|
{
|
||||||
return ((Connection)state).OnAlloc(handle, suggestedSize);
|
return ((Connection)state).OnAlloc(handle, suggestedSize);
|
||||||
|
|
@ -32,6 +29,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
private Frame _frame;
|
private Frame _frame;
|
||||||
long _connectionId = 0;
|
long _connectionId = 0;
|
||||||
|
|
||||||
|
private readonly object _stateLock = new object();
|
||||||
|
private ConnectionState _connectionState;
|
||||||
|
|
||||||
public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
|
public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
|
||||||
{
|
{
|
||||||
_socket = socket;
|
_socket = socket;
|
||||||
|
|
@ -104,62 +104,70 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
void IConnectionControl.End(ProduceEndType endType)
|
void IConnectionControl.End(ProduceEndType endType)
|
||||||
{
|
{
|
||||||
switch (endType)
|
lock (_stateLock)
|
||||||
{
|
{
|
||||||
case ProduceEndType.SocketShutdownSend:
|
switch (endType)
|
||||||
if (Interlocked.CompareExchange(ref _connectionState, ConnectionState.Shutdown, ConnectionState.Open)
|
{
|
||||||
!= ConnectionState.Open)
|
case ProduceEndType.SocketShutdownSend:
|
||||||
{
|
if (_connectionState != ConnectionState.Open)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
KestrelTrace.Log.ConnectionWriteFin(_connectionId, 0);
|
|
||||||
Thread.Post(
|
|
||||||
x =>
|
|
||||||
{
|
{
|
||||||
KestrelTrace.Log.ConnectionWriteFin(_connectionId, 1);
|
return;
|
||||||
var self = (Connection)x;
|
}
|
||||||
var shutdown = new UvShutdownReq();
|
_connectionState = ConnectionState.Shutdown;
|
||||||
shutdown.Init(self.Thread.Loop);
|
|
||||||
shutdown.Shutdown(self._socket, (req, status, state) =>
|
KestrelTrace.Log.ConnectionWriteFin(_connectionId, 0);
|
||||||
|
Thread.Post(
|
||||||
|
x =>
|
||||||
{
|
{
|
||||||
KestrelTrace.Log.ConnectionWriteFin(_connectionId, 1);
|
KestrelTrace.Log.ConnectionWriteFin(_connectionId, 1);
|
||||||
req.Dispose();
|
var self = (Connection)x;
|
||||||
}, null);
|
var shutdown = new UvShutdownReq();
|
||||||
},
|
shutdown.Init(self.Thread.Loop);
|
||||||
this);
|
shutdown.Shutdown(self._socket, (req, status, state) =>
|
||||||
break;
|
{
|
||||||
case ProduceEndType.ConnectionKeepAlive:
|
KestrelTrace.Log.ConnectionWriteFin(_connectionId, 1);
|
||||||
KestrelTrace.Log.ConnectionKeepAlive(_connectionId);
|
req.Dispose();
|
||||||
_frame = new Frame(this);
|
}, null);
|
||||||
Thread.Post(
|
},
|
||||||
x => ((Frame)x).Consume(),
|
this);
|
||||||
_frame);
|
break;
|
||||||
break;
|
case ProduceEndType.ConnectionKeepAlive:
|
||||||
case ProduceEndType.SocketDisconnect:
|
if (_connectionState != ConnectionState.Open)
|
||||||
if (Interlocked.Exchange(ref _connectionState, ConnectionState.Disconnected)
|
|
||||||
== ConnectionState.Disconnected)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
KestrelTrace.Log.ConnectionDisconnect(_connectionId);
|
|
||||||
Thread.Post(
|
|
||||||
x =>
|
|
||||||
{
|
{
|
||||||
KestrelTrace.Log.ConnectionStop(_connectionId);
|
return;
|
||||||
((UvHandle)x).Dispose();
|
}
|
||||||
},
|
|
||||||
_socket);
|
KestrelTrace.Log.ConnectionKeepAlive(_connectionId);
|
||||||
break;
|
_frame = new Frame(this);
|
||||||
|
Thread.Post(
|
||||||
|
x => ((Frame)x).Consume(),
|
||||||
|
_frame);
|
||||||
|
break;
|
||||||
|
case ProduceEndType.SocketDisconnect:
|
||||||
|
if (_connectionState == ConnectionState.Disconnected)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_connectionState = ConnectionState.Disconnected;
|
||||||
|
|
||||||
|
KestrelTrace.Log.ConnectionDisconnect(_connectionId);
|
||||||
|
Thread.Post(
|
||||||
|
x =>
|
||||||
|
{
|
||||||
|
KestrelTrace.Log.ConnectionStop(_connectionId);
|
||||||
|
((UvHandle)x).Dispose();
|
||||||
|
},
|
||||||
|
_socket);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ConnectionState
|
private enum ConnectionState
|
||||||
{
|
{
|
||||||
public const int Open = 0;
|
Open,
|
||||||
public const int Shutdown = 1;
|
Shutdown,
|
||||||
public const int Disconnected = 2;
|
Disconnected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue