Use TryEnter to acquire SocketOutput._contextLock on the libuv event loop

This commit is contained in:
Stephen Halter 2016-01-07 15:41:40 -08:00
parent e90b61e6c5
commit df695accb0
1 changed files with 53 additions and 24 deletions

View File

@ -9,6 +9,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.AspNet.Server.Kestrel.Networking; using Microsoft.AspNet.Server.Kestrel.Networking;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Server.Kestrel.Http namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
@ -278,7 +279,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
} }
} }
// This is called on the libuv event loop // This may called on the libuv event loop
// This is always called with the _contextLock already acquired
private void OnWriteCompleted(WriteContext writeContext) private void OnWriteCompleted(WriteContext writeContext)
{ {
var bytesWritten = writeContext.ByteCount; var bytesWritten = writeContext.ByteCount;
@ -294,8 +296,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_connection.Abort(); _connection.Abort();
} }
lock (_contextLock)
{
PoolWriteContext(writeContext); PoolWriteContext(writeContext);
// _numBytesPreCompleted can temporarily go negative in the event there are // _numBytesPreCompleted can temporarily go negative in the event there are
@ -316,7 +316,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_tasksCompleted.Enqueue(tcs); _tasksCompleted.Enqueue(tcs);
} }
}
while (_tasksCompleted.Count > 0) while (_tasksCompleted.Count > 0)
{ {
@ -414,6 +413,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private class WriteContext private class WriteContext
{ {
private static WaitCallback _returnWrittenBlocks = (state) => ReturnWrittenBlocks((MemoryPoolBlock2)state); private static WaitCallback _returnWrittenBlocks = (state) => ReturnWrittenBlocks((MemoryPoolBlock2)state);
private static WaitCallback _completeWrite = (state) => ((WriteContext)state).CompleteOnThreadPool();
private SocketOutput Self; private SocketOutput Self;
private UvWriteReq _writeReq; private UvWriteReq _writeReq;
@ -509,20 +509,49 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
if (SocketDisconnect == false || Self._socket.IsClosed) if (SocketDisconnect == false || Self._socket.IsClosed)
{ {
Complete(); CompleteOnUvThread();
return; return;
} }
Self._socket.Dispose(); Self._socket.Dispose();
Self.ReturnAllBlocks(); Self.ReturnAllBlocks();
Self._log.ConnectionStop(Self._connectionId); Self._log.ConnectionStop(Self._connectionId);
Complete(); CompleteOnUvThread();
} }
public void Complete() public void CompleteOnUvThread()
{
if (Monitor.TryEnter(Self._contextLock))
{
try
{ {
Self.OnWriteCompleted(this); Self.OnWriteCompleted(this);
} }
finally
{
Monitor.Exit(Self._contextLock);
}
}
else
{
ThreadPool.QueueUserWorkItem(_completeWrite, this);
}
}
public void CompleteOnThreadPool()
{
lock (Self._contextLock)
{
try
{
Self.OnWriteCompleted(this);
}
catch (Exception ex)
{
Self._log.LogError("SocketOutput.OnWriteCompleted", ex);
}
}
}
private void PoolWriteReq(UvWriteReq writeReq) private void PoolWriteReq(UvWriteReq writeReq)
{ {