From 34c1a671f04f4ff6b98766e1ca4a2d71891a7782 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sun, 1 Nov 2015 14:10:59 +0000 Subject: [PATCH 1/3] ListenerSecondary - reduce closure allocation --- .../Http/ListenerSecondary.cs | 185 ++++++++++-------- 1 file changed, 102 insertions(+), 83 deletions(-) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs index 814ea3ffe3..acff41bfeb 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs @@ -17,6 +17,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http /// public abstract class ListenerSecondary : ListenerContext, IDisposable { + private string _pipeName; + protected ListenerSecondary(ServiceContext serviceContext) : base(serviceContext) { } @@ -29,97 +31,114 @@ namespace Microsoft.AspNet.Server.Kestrel.Http KestrelThread thread, RequestDelegate application) { + _pipeName = pipeName; ServerAddress = address; Thread = thread; Application = application; DispatchPipe = new UvPipeHandle(Log); - var tcs = new TaskCompletionSource(); - Thread.Post(_ => - { - try - { - DispatchPipe.Init(Thread.Loop, true); - var connect = new UvConnectRequest(Log); - connect.Init(Thread.Loop); - connect.Connect( - DispatchPipe, - pipeName, - (connect2, status, error, state) => - { - connect.Dispose(); - if (error != null) - { - tcs.SetException(error); - return; - } - - try - { - var ptr = Marshal.AllocHGlobal(4); - var buf = Thread.Loop.Libuv.buf_init(ptr, 4); - - DispatchPipe.ReadStart( - (_1, _2, _3) => buf, - (_1, status2, state2) => - { - if (status2 < 0) - { - if (status2 != Constants.EOF) - { - Exception ex; - Thread.Loop.Libuv.Check(status2, out ex); - Log.LogError("DispatchPipe.ReadStart", ex); - } - - DispatchPipe.Dispose(); - Marshal.FreeHGlobal(ptr); - return; - } - - if (DispatchPipe.PendingCount() == 0) - { - return; - } - - var acceptSocket = CreateAcceptSocket(); - - try - { - DispatchPipe.Accept(acceptSocket); - } - catch (UvException ex) - { - Log.LogError("DispatchPipe.Accept", ex); - acceptSocket.Dispose(); - return; - } - - var connection = new Connection(this, acceptSocket); - connection.Start(); - }, - null); - - tcs.SetResult(0); - } - catch (Exception ex) - { - DispatchPipe.Dispose(); - tcs.SetException(ex); - } - }, - null); - } - catch (Exception ex) - { - DispatchPipe.Dispose(); - tcs.SetException(ex); - } - }, null); + var tcs = new TaskCompletionSource(this); + Thread.Post(tcs2 => StartCallback(tcs2), tcs); return tcs.Task; } + private static void StartCallback(TaskCompletionSource tcs) + { + var listener = (ListenerSecondary)tcs.Task.AsyncState; + listener.StartedCallback(tcs); + } + + private void StartedCallback(TaskCompletionSource tcs) + { + try + { + DispatchPipe.Init(Thread.Loop, true); + var connect = new UvConnectRequest(Log); + connect.Init(Thread.Loop); + connect.Connect( + DispatchPipe, + _pipeName, + (connect2, status, error, state) => ConnectCallback(connect2, status, error, (TaskCompletionSource)state), + tcs); + } + catch (Exception ex) + { + DispatchPipe.Dispose(); + tcs.SetException(ex); + } + } + + private static void ConnectCallback(UvConnectRequest connect, int status, Exception error, TaskCompletionSource tcs) + { + var listener = (ListenerSecondary)tcs.Task.AsyncState; + listener.ConnectedCallback(connect, status, error, tcs); + } + private void ConnectedCallback(UvConnectRequest connect, int status, Exception error, TaskCompletionSource tcs) + { + connect.Dispose(); + if (error != null) + { + tcs.SetException(error); + return; + } + + try + { + var ptr = Marshal.AllocHGlobal(4); + var buf = Thread.Loop.Libuv.buf_init(ptr, 4); + + DispatchPipe.ReadStart( + (handle, status2, state) => buf, + (handle, status2, state) => ((ListenerSecondary)state).ReadStartCallback(handle, status2, ptr), this); + + tcs.SetResult(0); + } + catch (Exception ex) + { + DispatchPipe.Dispose(); + tcs.SetException(ex); + } + } + + private void ReadStartCallback(UvStreamHandle handle, int status, IntPtr ptr) + { + if (status < 0) + { + if (status != Constants.EOF) + { + Exception ex; + Thread.Loop.Libuv.Check(status, out ex); + Log.LogError("DispatchPipe.ReadStart", ex); + } + + DispatchPipe.Dispose(); + Marshal.FreeHGlobal(ptr); + return; + } + + if (DispatchPipe.PendingCount() == 0) + { + return; + } + + var acceptSocket = CreateAcceptSocket(); + + try + { + DispatchPipe.Accept(acceptSocket); + } + catch (UvException ex) + { + Log.LogError("DispatchPipe.Accept", ex); + acceptSocket.Dispose(); + return; + } + + var connection = new Connection(this, acceptSocket); + connection.Start(); + } + /// /// Creates a socket which can be used to accept an incoming connection /// @@ -133,7 +152,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http // the exception that stopped the event loop will never be surfaced. if (Thread.FatalError == null) { - Thread.Send(_ => DispatchPipe.Dispose(), null); + Thread.Send(listener => ((ListenerSecondary)listener).DispatchPipe.Dispose(), this); } } } From 5cef608e5220d68268ac1e7274e81b745d68a04a Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 4 Nov 2015 22:20:51 +0000 Subject: [PATCH 2/3] Dispose _ptr --- .../Http/ListenerSecondary.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs index acff41bfeb..79e1ab89c1 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs @@ -18,6 +18,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http public abstract class ListenerSecondary : ListenerContext, IDisposable { private string _pipeName; + private IntPtr _ptr = IntPtr.Zero; + private Libuv.uv_buf_t _buf; protected ListenerSecondary(ServiceContext serviceContext) : base(serviceContext) { @@ -74,6 +76,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http var listener = (ListenerSecondary)tcs.Task.AsyncState; listener.ConnectedCallback(connect, status, error, tcs); } + private void ConnectedCallback(UvConnectRequest connect, int status, Exception error, TaskCompletionSource tcs) { connect.Dispose(); @@ -85,12 +88,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Http try { - var ptr = Marshal.AllocHGlobal(4); - var buf = Thread.Loop.Libuv.buf_init(ptr, 4); + _ptr = Marshal.AllocHGlobal(4); + _buf = Thread.Loop.Libuv.buf_init(_ptr, 4); DispatchPipe.ReadStart( - (handle, status2, state) => buf, - (handle, status2, state) => ((ListenerSecondary)state).ReadStartCallback(handle, status2, ptr), this); + (handle, status2, state) => ((ListenerSecondary)state)._buf, + (handle, status2, state) => + { + var listener = ((ListenerSecondary)state); + listener.ReadStartCallback(handle, status2, listener._ptr); + }, this); tcs.SetResult(0); } @@ -146,6 +153,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http public void Dispose() { + if (_ptr != IntPtr.Zero) + { + Marshal.FreeHGlobal(_ptr); + _ptr = IntPtr.Zero; + } + // Ensure the event loop is still running. // If the event loop isn't running and we try to wait on this Post // to complete, then KestrelEngine will never be disposed and From 3e7969cefe89ec38e9ed64658479ca04cf890515 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 4 Nov 2015 22:44:30 +0000 Subject: [PATCH 3/3] Move handle creation to constructor --- .../Http/ListenerSecondary.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs index 79e1ab89c1..d74c664e62 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs @@ -18,11 +18,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http public abstract class ListenerSecondary : ListenerContext, IDisposable { private string _pipeName; - private IntPtr _ptr = IntPtr.Zero; + private IntPtr _ptr; private Libuv.uv_buf_t _buf; protected ListenerSecondary(ServiceContext serviceContext) : base(serviceContext) { + _ptr = Marshal.AllocHGlobal(4); + _buf = Thread.Loop.Libuv.buf_init(_ptr, 4); } UvPipeHandle DispatchPipe { get; set; } @@ -88,9 +90,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http try { - _ptr = Marshal.AllocHGlobal(4); - _buf = Thread.Loop.Libuv.buf_init(_ptr, 4); - DispatchPipe.ReadStart( (handle, status2, state) => ((ListenerSecondary)state)._buf, (handle, status2, state) => @@ -153,11 +152,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http public void Dispose() { - if (_ptr != IntPtr.Zero) - { - Marshal.FreeHGlobal(_ptr); - _ptr = IntPtr.Zero; - } + Marshal.FreeHGlobal(_ptr); // Ensure the event loop is still running. // If the event loop isn't running and we try to wait on this Post