From 32c4f314b6063823b073d92e62ead05de2323069 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Fri, 14 Aug 2015 12:17:06 -0700 Subject: [PATCH] Lock around Connection.End to make it thread-safe --- .../Http/Connection.cs | 108 ++++++++++-------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs index a2976c75c9..641d184f8c 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs @@ -4,7 +4,6 @@ using System; using Microsoft.AspNet.Server.Kestrel.Networking; using System.Diagnostics; -using System.Threading; namespace Microsoft.AspNet.Server.Kestrel.Http { @@ -16,8 +15,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http private static readonly Action _readCallback = ReadCallback; private static readonly Func _allocCallback = AllocCallback; - private int _connectionState; - private static Libuv.uv_buf_t AllocCallback(UvStreamHandle handle, int suggestedSize, object state) { return ((Connection)state).OnAlloc(handle, suggestedSize); @@ -32,6 +29,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http private Frame _frame; long _connectionId = 0; + private readonly object _stateLock = new object(); + private ConnectionState _connectionState; + public Connection(ListenerContext context, UvStreamHandle socket) : base(context) { _socket = socket; @@ -104,62 +104,70 @@ namespace Microsoft.AspNet.Server.Kestrel.Http void IConnectionControl.End(ProduceEndType endType) { - switch (endType) + lock (_stateLock) { - case ProduceEndType.SocketShutdownSend: - if (Interlocked.CompareExchange(ref _connectionState, ConnectionState.Shutdown, ConnectionState.Open) - != ConnectionState.Open) - { - return; - } - - KestrelTrace.Log.ConnectionWriteFin(_connectionId, 0); - Thread.Post( - x => + switch (endType) + { + case ProduceEndType.SocketShutdownSend: + if (_connectionState != ConnectionState.Open) { - KestrelTrace.Log.ConnectionWriteFin(_connectionId, 1); - var self = (Connection)x; - var shutdown = new UvShutdownReq(); - shutdown.Init(self.Thread.Loop); - shutdown.Shutdown(self._socket, (req, status, state) => + return; + } + _connectionState = ConnectionState.Shutdown; + + KestrelTrace.Log.ConnectionWriteFin(_connectionId, 0); + Thread.Post( + x => { KestrelTrace.Log.ConnectionWriteFin(_connectionId, 1); - req.Dispose(); - }, null); - }, - this); - break; - case ProduceEndType.ConnectionKeepAlive: - KestrelTrace.Log.ConnectionKeepAlive(_connectionId); - _frame = new Frame(this); - Thread.Post( - x => ((Frame)x).Consume(), - _frame); - break; - case ProduceEndType.SocketDisconnect: - if (Interlocked.Exchange(ref _connectionState, ConnectionState.Disconnected) - == ConnectionState.Disconnected) - { - return; - } - - KestrelTrace.Log.ConnectionDisconnect(_connectionId); - Thread.Post( - x => + var self = (Connection)x; + var shutdown = new UvShutdownReq(); + shutdown.Init(self.Thread.Loop); + shutdown.Shutdown(self._socket, (req, status, state) => + { + KestrelTrace.Log.ConnectionWriteFin(_connectionId, 1); + req.Dispose(); + }, null); + }, + this); + break; + case ProduceEndType.ConnectionKeepAlive: + if (_connectionState != ConnectionState.Open) { - KestrelTrace.Log.ConnectionStop(_connectionId); - ((UvHandle)x).Dispose(); - }, - _socket); - break; + return; + } + + KestrelTrace.Log.ConnectionKeepAlive(_connectionId); + _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; - public const int Shutdown = 1; - public const int Disconnected = 2; + Open, + Shutdown, + Disconnected } } }