Merge branch 'benaadams/listenersecondary-allocs' into dev

This commit is contained in:
Stephen Halter 2015-11-04 15:34:42 -08:00
commit 74f08c16df
1 changed files with 110 additions and 83 deletions

View File

@ -17,8 +17,14 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
/// </summary> /// </summary>
public abstract class ListenerSecondary : ListenerContext, IDisposable public abstract class ListenerSecondary : ListenerContext, IDisposable
{ {
private string _pipeName;
private IntPtr _ptr;
private Libuv.uv_buf_t _buf;
protected ListenerSecondary(ServiceContext serviceContext) : base(serviceContext) protected ListenerSecondary(ServiceContext serviceContext) : base(serviceContext)
{ {
_ptr = Marshal.AllocHGlobal(4);
_buf = Thread.Loop.Libuv.buf_init(_ptr, 4);
} }
UvPipeHandle DispatchPipe { get; set; } UvPipeHandle DispatchPipe { get; set; }
@ -29,14 +35,25 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
KestrelThread thread, KestrelThread thread,
RequestDelegate application) RequestDelegate application)
{ {
_pipeName = pipeName;
ServerAddress = address; ServerAddress = address;
Thread = thread; Thread = thread;
Application = application; Application = application;
DispatchPipe = new UvPipeHandle(Log); DispatchPipe = new UvPipeHandle(Log);
var tcs = new TaskCompletionSource<int>(); var tcs = new TaskCompletionSource<int>(this);
Thread.Post(_ => Thread.Post(tcs2 => StartCallback(tcs2), tcs);
return tcs.Task;
}
private static void StartCallback(TaskCompletionSource<int> tcs)
{
var listener = (ListenerSecondary)tcs.Task.AsyncState;
listener.StartedCallback(tcs);
}
private void StartedCallback(TaskCompletionSource<int> tcs)
{ {
try try
{ {
@ -45,8 +62,24 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
connect.Init(Thread.Loop); connect.Init(Thread.Loop);
connect.Connect( connect.Connect(
DispatchPipe, DispatchPipe,
pipeName, _pipeName,
(connect2, status, error, state) => (connect2, status, error, state) => ConnectCallback(connect2, status, error, (TaskCompletionSource<int>)state),
tcs);
}
catch (Exception ex)
{
DispatchPipe.Dispose();
tcs.SetException(ex);
}
}
private static void ConnectCallback(UvConnectRequest connect, int status, Exception error, TaskCompletionSource<int> tcs)
{
var listener = (ListenerSecondary)tcs.Task.AsyncState;
listener.ConnectedCallback(connect, status, error, tcs);
}
private void ConnectedCallback(UvConnectRequest connect, int status, Exception error, TaskCompletionSource<int> tcs)
{ {
connect.Dispose(); connect.Dispose();
if (error != null) if (error != null)
@ -57,19 +90,31 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
try try
{ {
var ptr = Marshal.AllocHGlobal(4);
var buf = Thread.Loop.Libuv.buf_init(ptr, 4);
DispatchPipe.ReadStart( DispatchPipe.ReadStart(
(_1, _2, _3) => buf, (handle, status2, state) => ((ListenerSecondary)state)._buf,
(_1, status2, state2) => (handle, status2, state) =>
{ {
if (status2 < 0) var listener = ((ListenerSecondary)state);
listener.ReadStartCallback(handle, status2, listener._ptr);
}, this);
tcs.SetResult(0);
}
catch (Exception ex)
{ {
if (status2 != Constants.EOF) DispatchPipe.Dispose();
tcs.SetException(ex);
}
}
private void ReadStartCallback(UvStreamHandle handle, int status, IntPtr ptr)
{
if (status < 0)
{
if (status != Constants.EOF)
{ {
Exception ex; Exception ex;
Thread.Loop.Libuv.Check(status2, out ex); Thread.Loop.Libuv.Check(status, out ex);
Log.LogError("DispatchPipe.ReadStart", ex); Log.LogError("DispatchPipe.ReadStart", ex);
} }
@ -98,26 +143,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
var connection = new Connection(this, acceptSocket); var connection = new Connection(this, acceptSocket);
connection.Start(); connection.Start();
},
null);
tcs.SetResult(0);
}
catch (Exception ex)
{
DispatchPipe.Dispose();
tcs.SetException(ex);
}
},
null);
}
catch (Exception ex)
{
DispatchPipe.Dispose();
tcs.SetException(ex);
}
}, null);
return tcs.Task;
} }
/// <summary> /// <summary>
@ -127,13 +152,15 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public void Dispose() public void Dispose()
{ {
Marshal.FreeHGlobal(_ptr);
// Ensure the event loop is still running. // Ensure the event loop is still running.
// If the event loop isn't running and we try to wait on this Post // If the event loop isn't running and we try to wait on this Post
// to complete, then KestrelEngine will never be disposed and // to complete, then KestrelEngine will never be disposed and
// the exception that stopped the event loop will never be surfaced. // the exception that stopped the event loop will never be surfaced.
if (Thread.FatalError == null) if (Thread.FatalError == null)
{ {
Thread.Send(_ => DispatchPipe.Dispose(), null); Thread.Send(listener => ((ListenerSecondary)listener).DispatchPipe.Dispose(), this);
} }
} }
} }