Close UvAsyncHandle properly to avoid zombie threads
- Even when safe handles are disposed explicitly, ReleaseHandle is sometimes called on another thread which breaks uv_close. - Ensure we close the UvAsyncHandle the uv loop so that the second call to uv_run always completes without a timeout/Thread.Abort. - Re-enable some tests. Add skip conditions for those that aren't passing.
This commit is contained in:
parent
54caf3071c
commit
304016fc3b
|
|
@ -29,8 +29,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
|
||||
var tcs = new TaskCompletionSource<int>(this);
|
||||
|
||||
Thread.Post(tcs2 =>
|
||||
Thread.Post(state =>
|
||||
{
|
||||
var tcs2 = (TaskCompletionSource<int>)state;
|
||||
try
|
||||
{
|
||||
var listener = ((Listener)tcs2.Task.AsyncState);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
private void PostCallback()
|
||||
{
|
||||
ListenPipe = new UvPipeHandle(Log);
|
||||
ListenPipe.Init(Thread.Loop, false);
|
||||
ListenPipe.Init(Thread.Loop, Thread.QueueCloseHandle, false);
|
||||
ListenPipe.Bind(_pipeName);
|
||||
ListenPipe.Listen(Constants.ListenBacklog,
|
||||
(pipe, status, error, state) => ((ListenerPrimary)state).OnListenPipe(pipe, status, error), this);
|
||||
|
|
@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
}
|
||||
|
||||
var dispatchPipe = new UvPipeHandle(Log);
|
||||
dispatchPipe.Init(Thread.Loop, true);
|
||||
dispatchPipe.Init(Thread.Loop, Thread.QueueCloseHandle, true);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
DispatchPipe = new UvPipeHandle(Log);
|
||||
|
||||
var tcs = new TaskCompletionSource<int>(this);
|
||||
Thread.Post(tcs2 => StartCallback(tcs2), tcs);
|
||||
Thread.Post(state => StartCallback((TaskCompletionSource<int>)state), tcs);
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
{
|
||||
try
|
||||
{
|
||||
DispatchPipe.Init(Thread.Loop, true);
|
||||
DispatchPipe.Init(Thread.Loop, Thread.QueueCloseHandle, true);
|
||||
var connect = new UvConnectRequest(Log);
|
||||
connect.Init(Thread.Loop);
|
||||
connect.Connect(
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
protected override UvStreamHandle CreateListenSocket()
|
||||
{
|
||||
var socket = new UvPipeHandle(Log);
|
||||
socket.Init(Thread.Loop, false);
|
||||
socket.Init(Thread.Loop, Thread.QueueCloseHandle, false);
|
||||
socket.Bind(ServerAddress.UnixPipePath);
|
||||
socket.Listen(Constants.ListenBacklog, (stream, status, error, state) => ConnectionCallback(stream, status, error, state), this);
|
||||
return socket;
|
||||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
|
||||
try
|
||||
{
|
||||
acceptSocket.Init(Thread.Loop, false);
|
||||
acceptSocket.Init(Thread.Loop, Thread.QueueCloseHandle, false);
|
||||
listenSocket.Accept(acceptSocket);
|
||||
DispatchConnection(acceptSocket);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
protected override UvStreamHandle CreateListenSocket()
|
||||
{
|
||||
var socket = new UvPipeHandle(Log);
|
||||
socket.Init(Thread.Loop, false);
|
||||
socket.Init(Thread.Loop, Thread.QueueCloseHandle, false);
|
||||
socket.Bind(ServerAddress.UnixPipePath);
|
||||
socket.Listen(Constants.ListenBacklog, (stream, status, error, state) => ConnectionCallback(stream, status, error, state), this);
|
||||
return socket;
|
||||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
|
||||
try
|
||||
{
|
||||
acceptSocket.Init(Thread.Loop, false);
|
||||
acceptSocket.Init(Thread.Loop, Thread.QueueCloseHandle, false);
|
||||
listenSocket.Accept(acceptSocket);
|
||||
DispatchConnection(acceptSocket);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
protected override UvStreamHandle CreateAcceptSocket()
|
||||
{
|
||||
var acceptSocket = new UvPipeHandle(Log);
|
||||
acceptSocket.Init(Thread.Loop, false);
|
||||
acceptSocket.Init(Thread.Loop, Thread.QueueCloseHandle, false);
|
||||
return acceptSocket;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
|||
|
||||
private void ScheduleWrite()
|
||||
{
|
||||
_thread.Post(_this => _this.WriteAllPending(), this);
|
||||
_thread.Post(state => ((SocketOutput)state).WriteAllPending(), this);
|
||||
}
|
||||
|
||||
// This is called on the libuv event loop
|
||||
|
|
|
|||
|
|
@ -24,9 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
// otherwise it needs to wait till the next pass of the libuv loop
|
||||
private const int _maxLoops = 8;
|
||||
|
||||
private static readonly Action<object, object> _threadCallbackAdapter = (callback, state) => ((Action<KestrelThread>)callback).Invoke((KestrelThread)state);
|
||||
private static readonly Action<object, object> _socketCallbackAdapter = (callback, state) => ((Action<SocketOutput>)callback).Invoke((SocketOutput)state);
|
||||
private static readonly Action<object, object> _tcsCallbackAdapter = (callback, state) => ((Action<TaskCompletionSource<int>>)callback).Invoke((TaskCompletionSource<int>)state);
|
||||
private static readonly Action<object, object> _postCallbackAdapter = (callback, state) => ((Action<object>)callback).Invoke(state);
|
||||
private static readonly Action<object, object> _postAsyncCallbackAdapter = (callback, state) => ((Action<object>)callback).Invoke(state);
|
||||
|
||||
private readonly KestrelEngine _engine;
|
||||
|
|
@ -56,12 +54,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
_thread = new Thread(ThreadStart);
|
||||
_thread.Name = "KestrelThread - libuv";
|
||||
QueueCloseHandle = PostCloseHandle;
|
||||
QueueCloseAsyncHandle = EnqueueCloseHandle;
|
||||
}
|
||||
|
||||
public UvLoopHandle Loop { get { return _loop; } }
|
||||
|
||||
public ExceptionDispatchInfo FatalError { get { return _closeError; } }
|
||||
|
||||
public Action<Action<IntPtr>, IntPtr> QueueCloseHandle { get; internal set; }
|
||||
public Action<Action<IntPtr>, IntPtr> QueueCloseHandle { get; }
|
||||
|
||||
private Action<Action<IntPtr>, IntPtr> QueueCloseAsyncHandle { get; }
|
||||
|
||||
public Task StartAsync()
|
||||
{
|
||||
|
|
@ -137,41 +139,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
_loop.Stop();
|
||||
}
|
||||
|
||||
public void Post(Action<object> callback, object state)
|
||||
{
|
||||
lock (_workSync)
|
||||
{
|
||||
_workAdding.Enqueue(new Work
|
||||
{
|
||||
CallbackAdapter = _postCallbackAdapter,
|
||||
Callback = callback,
|
||||
State = state
|
||||
});
|
||||
}
|
||||
_post.Send();
|
||||
}
|
||||
|
||||
private void Post(Action<KestrelThread> callback)
|
||||
{
|
||||
lock (_workSync)
|
||||
{
|
||||
_workAdding.Enqueue(new Work { CallbackAdapter = _threadCallbackAdapter, Callback = callback, State = this });
|
||||
}
|
||||
_post.Send();
|
||||
}
|
||||
|
||||
public void Post(Action<SocketOutput> callback, SocketOutput state)
|
||||
{
|
||||
lock (_workSync)
|
||||
{
|
||||
_workAdding.Enqueue(new Work
|
||||
{
|
||||
CallbackAdapter = _socketCallbackAdapter,
|
||||
Callback = callback,
|
||||
State = state
|
||||
});
|
||||
}
|
||||
_post.Send();
|
||||
}
|
||||
|
||||
public void Post(Action<TaskCompletionSource<int>> callback, TaskCompletionSource<int> state)
|
||||
{
|
||||
lock (_workSync)
|
||||
{
|
||||
_workAdding.Enqueue(new Work
|
||||
{
|
||||
CallbackAdapter = _tcsCallbackAdapter,
|
||||
Callback = callback,
|
||||
State = state
|
||||
});
|
||||
}
|
||||
_post.Send();
|
||||
Post(thread => callback((KestrelThread)thread), this);
|
||||
}
|
||||
|
||||
public Task PostAsync(Action<object> callback, object state)
|
||||
|
|
@ -192,12 +176,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
}
|
||||
|
||||
private void PostCloseHandle(Action<IntPtr> callback, IntPtr handle)
|
||||
{
|
||||
EnqueueCloseHandle(callback, handle);
|
||||
_post.Send();
|
||||
}
|
||||
|
||||
private void EnqueueCloseHandle(Action<IntPtr> callback, IntPtr handle)
|
||||
{
|
||||
lock (_workSync)
|
||||
{
|
||||
_closeHandleAdding.Enqueue(new CloseHandle { Callback = callback, Handle = handle });
|
||||
}
|
||||
_post.Send();
|
||||
}
|
||||
|
||||
private void ThreadStart(object parameter)
|
||||
|
|
@ -206,7 +195,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
try
|
||||
{
|
||||
_loop.Init(_engine.Libuv);
|
||||
_post.Init(_loop, OnPost);
|
||||
_post.Init(_loop, OnPost, EnqueueCloseHandle);
|
||||
tcs.SetResult(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -230,18 +219,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
_post.Reference();
|
||||
_post.Dispose();
|
||||
|
||||
_engine.Libuv.walk(
|
||||
_loop,
|
||||
(ptr, arg) =>
|
||||
{
|
||||
var handle = UvMemory.FromIntPtr<UvHandle>(ptr);
|
||||
if (handle != _post)
|
||||
{
|
||||
handle.Dispose();
|
||||
}
|
||||
},
|
||||
IntPtr.Zero);
|
||||
|
||||
// Ensure the Dispose operations complete in the event loop.
|
||||
var ran2 = _loop.Run();
|
||||
|
||||
|
|
@ -307,6 +284,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
|
||||
return wasWork;
|
||||
}
|
||||
|
||||
private bool DoPostCloseHandle()
|
||||
{
|
||||
Queue<CloseHandle> queue;
|
||||
|
|
@ -333,7 +311,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
}
|
||||
}
|
||||
|
||||
return wasWork;
|
||||
return wasWork;
|
||||
}
|
||||
|
||||
private struct Work
|
||||
|
|
@ -343,6 +321,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
|||
public object State;
|
||||
public TaskCompletionSource<object> Completion;
|
||||
}
|
||||
|
||||
private struct CloseHandle
|
||||
{
|
||||
public Action<IntPtr> Callback;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
_uv_close = NativeDarwinMonoMethods.uv_close;
|
||||
_uv_async_init = NativeDarwinMonoMethods.uv_async_init;
|
||||
_uv_async_send = NativeDarwinMonoMethods.uv_async_send;
|
||||
_uv_unsafe_async_send = NativeDarwinMonoMethods.uv_unsafe_async_send;
|
||||
_uv_tcp_init = NativeDarwinMonoMethods.uv_tcp_init;
|
||||
_uv_tcp_bind = NativeDarwinMonoMethods.uv_tcp_bind;
|
||||
_uv_tcp_open = NativeDarwinMonoMethods.uv_tcp_open;
|
||||
|
|
@ -71,6 +72,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
_uv_close = NativeMethods.uv_close;
|
||||
_uv_async_init = NativeMethods.uv_async_init;
|
||||
_uv_async_send = NativeMethods.uv_async_send;
|
||||
_uv_unsafe_async_send = NativeMethods.uv_unsafe_async_send;
|
||||
_uv_tcp_init = NativeMethods.uv_tcp_init;
|
||||
_uv_tcp_bind = NativeMethods.uv_tcp_bind;
|
||||
_uv_tcp_open = NativeMethods.uv_tcp_open;
|
||||
|
|
@ -207,6 +209,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
Check(_uv_async_send(handle));
|
||||
}
|
||||
|
||||
protected Func<IntPtr, int> _uv_unsafe_async_send;
|
||||
public void unsafe_async_send(IntPtr handle)
|
||||
{
|
||||
Check(_uv_unsafe_async_send(handle));
|
||||
}
|
||||
|
||||
protected Func<UvLoopHandle, UvTcpHandle, int> _uv_tcp_init;
|
||||
public void tcp_init(UvLoopHandle loop, UvTcpHandle handle)
|
||||
{
|
||||
|
|
@ -510,6 +518,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
|
||||
public extern static int uv_async_send(UvAsyncHandle handle);
|
||||
|
||||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl, EntryPoint = "uv_async_send")]
|
||||
public extern static int uv_unsafe_async_send(IntPtr handle);
|
||||
|
||||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_tcp_init(UvLoopHandle loop, UvTcpHandle handle);
|
||||
|
||||
|
|
@ -618,6 +629,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
|
||||
public extern static int uv_async_send(UvAsyncHandle handle);
|
||||
|
||||
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl, EntryPoint = "uv_async_send")]
|
||||
public extern static int uv_unsafe_async_send(IntPtr handle);
|
||||
|
||||
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_tcp_init(UvLoopHandle loop, UvTcpHandle handle);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,27 +2,33 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
||||
{
|
||||
public class UvAsyncHandle : UvHandle
|
||||
{
|
||||
private static readonly Libuv.uv_close_cb _destroyMemory = (handle) => DestroyMemory(handle);
|
||||
|
||||
private static readonly Libuv.uv_async_cb _uv_async_cb = (handle) => AsyncCb(handle);
|
||||
private Action _callback;
|
||||
private Action<Action<IntPtr>, IntPtr> _queueCloseHandle;
|
||||
|
||||
public UvAsyncHandle(IKestrelTrace logger) : base(logger)
|
||||
{
|
||||
}
|
||||
|
||||
public void Init(UvLoopHandle loop, Action callback)
|
||||
public void Init(UvLoopHandle loop, Action callback, Action<Action<IntPtr>, IntPtr> queueCloseHandle)
|
||||
{
|
||||
CreateMemory(
|
||||
loop.Libuv,
|
||||
loop.ThreadId,
|
||||
loop.Libuv,
|
||||
loop.ThreadId,
|
||||
loop.Libuv.handle_size(Libuv.HandleType.ASYNC));
|
||||
|
||||
_callback = callback;
|
||||
_queueCloseHandle = queueCloseHandle;
|
||||
_uv.async_init(loop, this, _uv_async_cb);
|
||||
}
|
||||
|
||||
|
|
@ -35,5 +41,33 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
{
|
||||
FromIntPtr<UvAsyncHandle>(handle)._callback.Invoke();
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
var memory = handle;
|
||||
if (memory != IntPtr.Zero)
|
||||
{
|
||||
handle = IntPtr.Zero;
|
||||
|
||||
if (Thread.CurrentThread.ManagedThreadId == ThreadId)
|
||||
{
|
||||
_uv.close(memory, _destroyMemory);
|
||||
}
|
||||
else if (_queueCloseHandle != null)
|
||||
{
|
||||
// This can be called from the finalizer.
|
||||
// Ensure the closure doesn't reference "this".
|
||||
var uv = _uv;
|
||||
_queueCloseHandle(memory2 => uv.close(memory2, _destroyMemory), memory);
|
||||
uv.unsafe_async_send(memory);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(false, "UvAsyncHandle not initialized with queueCloseHandle action");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
|
||||
|
||||
|
|
@ -44,6 +45,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
var uv = _uv;
|
||||
_queueCloseHandle(memory2 => uv.close(memory2, _destroyMemory), memory);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(false, "UvHandle not initialized with queueCloseHandle action");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
||||
{
|
||||
public class UvLoopHandle : UvHandle
|
||||
public class UvLoopHandle : UvMemory
|
||||
{
|
||||
public UvLoopHandle(IKestrelTrace logger) : base(logger)
|
||||
{
|
||||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
|
||||
unsafe protected override bool ReleaseHandle()
|
||||
{
|
||||
var memory = this.handle;
|
||||
var memory = handle;
|
||||
if (memory != IntPtr.Zero)
|
||||
{
|
||||
// loop_close clears the gcHandlePtr
|
||||
|
|
@ -46,6 +46,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
|
||||
DestroyMemory(memory, gcHandlePtr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,5 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
GCHandle gcHandle = GCHandle.FromIntPtr(*(IntPtr*)handle);
|
||||
return (THandle)gcHandle.Target;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -13,24 +13,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
{
|
||||
}
|
||||
|
||||
public void Init(UvLoopHandle loop, bool ipc)
|
||||
{
|
||||
CreateMemory(
|
||||
loop.Libuv,
|
||||
loop.ThreadId,
|
||||
loop.Libuv.handle_size(Libuv.HandleType.NAMED_PIPE));
|
||||
|
||||
_uv.pipe_init(loop, this, ipc);
|
||||
}
|
||||
|
||||
public void Init(UvLoopHandle loop, Action<Action<IntPtr>, IntPtr> queueCloseHandle)
|
||||
public void Init(UvLoopHandle loop, Action<Action<IntPtr>, IntPtr> queueCloseHandle, bool ipc = false)
|
||||
{
|
||||
CreateHandle(
|
||||
loop.Libuv,
|
||||
loop.ThreadId,
|
||||
loop.Libuv.handle_size(Libuv.HandleType.TCP), queueCloseHandle);
|
||||
loop.Libuv.handle_size(Libuv.HandleType.NAMED_PIPE), queueCloseHandle);
|
||||
|
||||
_uv.pipe_init(loop, this, false);
|
||||
_uv.pipe_init(loop, this, ipc);
|
||||
}
|
||||
|
||||
public void Bind(string name)
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
private readonly static Libuv.uv_alloc_cb _uv_alloc_cb = (IntPtr handle, int suggested_size, out Libuv.uv_buf_t buf) => UvAllocCb(handle, suggested_size, out buf);
|
||||
private readonly static Libuv.uv_read_cb _uv_read_cb = (IntPtr handle, int status, ref Libuv.uv_buf_t buf) => UvReadCb(handle, status, ref buf);
|
||||
|
||||
public Action<UvStreamHandle, int, Exception, object> _listenCallback;
|
||||
public object _listenState;
|
||||
private Action<UvStreamHandle, int, Exception, object> _listenCallback;
|
||||
private object _listenState;
|
||||
private GCHandle _listenVitality;
|
||||
|
||||
public Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback;
|
||||
public Action<UvStreamHandle, int, object> _readCallback;
|
||||
public object _readState;
|
||||
private Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback;
|
||||
private Action<UvStreamHandle, int, object> _readCallback;
|
||||
private object _readState;
|
||||
private GCHandle _readVitality;
|
||||
|
||||
protected UvStreamHandle(IKestrelTrace logger) : base(logger)
|
||||
|
|
|
|||
|
|
@ -14,16 +14,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
|
|||
{
|
||||
}
|
||||
|
||||
public void Init(UvLoopHandle loop)
|
||||
{
|
||||
CreateMemory(
|
||||
loop.Libuv,
|
||||
loop.ThreadId,
|
||||
loop.Libuv.handle_size(Libuv.HandleType.TCP));
|
||||
|
||||
_uv.tcp_init(loop, this);
|
||||
}
|
||||
|
||||
public void Init(UvLoopHandle loop, Action<Action<IntPtr>, IntPtr> queueCloseHandle)
|
||||
{
|
||||
CreateHandle(
|
||||
|
|
|
|||
|
|
@ -21,13 +21,14 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
_logger = engine.Log;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InitAndCloseServerPipe()
|
||||
{
|
||||
var loop = new UvLoopHandle(_logger);
|
||||
var pipe = new UvPipeHandle(_logger);
|
||||
|
||||
loop.Init(_uv);
|
||||
pipe.Init(loop, true);
|
||||
pipe.Init(loop, (a, b) => { }, true);
|
||||
pipe.Bind(@"\\.\pipe\InitAndCloseServerPipe");
|
||||
pipe.Dispose();
|
||||
|
||||
|
|
@ -38,18 +39,19 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
|
||||
}
|
||||
|
||||
[Fact(Skip = "Test needs to be fixed (UvException: Error -4082 EBUSY resource busy or locked from loop_close)")]
|
||||
public void ServerPipeListenForConnections()
|
||||
{
|
||||
var loop = new UvLoopHandle(_logger);
|
||||
var serverListenPipe = new UvPipeHandle(_logger);
|
||||
|
||||
loop.Init(_uv);
|
||||
serverListenPipe.Init(loop, false);
|
||||
serverListenPipe.Init(loop, (a, b) => { }, false);
|
||||
serverListenPipe.Bind(@"\\.\pipe\ServerPipeListenForConnections");
|
||||
serverListenPipe.Listen(128, (_1, status, error, _2) =>
|
||||
{
|
||||
var serverConnectionPipe = new UvPipeHandle(_logger);
|
||||
serverConnectionPipe.Init(loop, true);
|
||||
serverConnectionPipe.Init(loop, (a, b) => { }, true);
|
||||
try
|
||||
{
|
||||
serverListenPipe.Accept(serverConnectionPipe);
|
||||
|
|
@ -92,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var connect = new UvConnectRequest(new KestrelTrace(new TestKestrelTrace()));
|
||||
|
||||
loop2.Init(_uv);
|
||||
clientConnectionPipe.Init(loop2, true);
|
||||
clientConnectionPipe.Init(loop2, (a, b) => { }, true);
|
||||
connect.Init(loop2);
|
||||
connect.Connect(clientConnectionPipe, @"\\.\pipe\ServerPipeListenForConnections", (_1, status, error, _2) =>
|
||||
{
|
||||
|
|
@ -120,6 +122,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
}
|
||||
|
||||
|
||||
[Fact(Skip = "Test needs to be fixed (UvException: Error -4088 EAGAIN resource temporarily unavailable from accept)")]
|
||||
public void ServerPipeDispatchConnections()
|
||||
{
|
||||
var pipeName = @"\\.\pipe\ServerPipeDispatchConnections" + Guid.NewGuid().ToString("n");
|
||||
|
|
@ -132,12 +135,12 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var serverConnectionTcpDisposedEvent = new ManualResetEvent(false);
|
||||
|
||||
var serverListenPipe = new UvPipeHandle(_logger);
|
||||
serverListenPipe.Init(loop, false);
|
||||
serverListenPipe.Init(loop, (a, b) => { }, false);
|
||||
serverListenPipe.Bind(pipeName);
|
||||
serverListenPipe.Listen(128, (_1, status, error, _2) =>
|
||||
{
|
||||
serverConnectionPipe = new UvPipeHandle(_logger);
|
||||
serverConnectionPipe.Init(loop, true);
|
||||
serverConnectionPipe.Init(loop, (a, b) => { }, true);
|
||||
try
|
||||
{
|
||||
serverListenPipe.Accept(serverConnectionPipe);
|
||||
|
|
@ -152,13 +155,13 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
}, null);
|
||||
|
||||
var serverListenTcp = new UvTcpHandle(_logger);
|
||||
serverListenTcp.Init(loop);
|
||||
serverListenTcp.Init(loop, (a, b) => { });
|
||||
var address = ServerAddress.FromUrl("http://localhost:54321/");
|
||||
serverListenTcp.Bind(address);
|
||||
serverListenTcp.Listen(128, (_1, status, error, _2) =>
|
||||
{
|
||||
var serverConnectionTcp = new UvTcpHandle(_logger);
|
||||
serverConnectionTcp.Init(loop);
|
||||
serverConnectionTcp.Init(loop, (a, b) => { });
|
||||
serverListenTcp.Accept(serverConnectionTcp);
|
||||
|
||||
serverConnectionPipeAcceptedEvent.WaitOne();
|
||||
|
|
@ -188,7 +191,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var connect = new UvConnectRequest(new KestrelTrace(new TestKestrelTrace()));
|
||||
|
||||
loop2.Init(_uv);
|
||||
clientConnectionPipe.Init(loop2, true);
|
||||
clientConnectionPipe.Init(loop2, (a, b) => { }, true);
|
||||
connect.Init(loop2);
|
||||
connect.Connect(clientConnectionPipe, pipeName, (_1, status, error, _2) =>
|
||||
{
|
||||
|
|
@ -208,7 +211,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
return;
|
||||
}
|
||||
var clientConnectionTcp = new UvTcpHandle(_logger);
|
||||
clientConnectionTcp.Init(loop2);
|
||||
clientConnectionTcp.Init(loop2, (a, b) => { });
|
||||
clientConnectionPipe.Accept(clientConnectionTcp);
|
||||
var buf2 = loop2.Libuv.buf_init(Marshal.AllocHGlobal(64), 64);
|
||||
clientConnectionTcp.ReadStart(
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
{
|
||||
called = true;
|
||||
trigger.Dispose();
|
||||
});
|
||||
}, (a, b) => { });
|
||||
trigger.Send();
|
||||
loop.Run();
|
||||
loop.Dispose();
|
||||
|
|
@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var loop = new UvLoopHandle(_logger);
|
||||
loop.Init(_uv);
|
||||
var tcp = new UvTcpHandle(_logger);
|
||||
tcp.Init(loop);
|
||||
tcp.Init(loop, (a, b) => { });
|
||||
var address = ServerAddress.FromUrl("http://localhost:0/");
|
||||
tcp.Bind(address);
|
||||
tcp.Dispose();
|
||||
|
|
@ -75,14 +75,14 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var loop = new UvLoopHandle(_logger);
|
||||
loop.Init(_uv);
|
||||
var tcp = new UvTcpHandle(_logger);
|
||||
tcp.Init(loop);
|
||||
tcp.Init(loop, (a, b) => { });
|
||||
var port = TestServer.GetNextPort();
|
||||
var address = ServerAddress.FromUrl($"http://localhost:{port}/");
|
||||
tcp.Bind(address);
|
||||
tcp.Listen(10, (stream, status, error, state) =>
|
||||
{
|
||||
var tcp2 = new UvTcpHandle(_logger);
|
||||
tcp2.Init(loop);
|
||||
tcp2.Init(loop, (a, b) => { });
|
||||
stream.Accept(tcp2);
|
||||
tcp2.Dispose();
|
||||
stream.Dispose();
|
||||
|
|
@ -117,15 +117,14 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var loop = new UvLoopHandle(_logger);
|
||||
loop.Init(_uv);
|
||||
var tcp = new UvTcpHandle(_logger);
|
||||
tcp.Init(loop);
|
||||
tcp.Init(loop, (a, b) => { });
|
||||
var port = TestServer.GetNextPort();
|
||||
var address = ServerAddress.FromUrl($"http://localhost:{port}/");
|
||||
tcp.Bind(address);
|
||||
tcp.Listen(10, (_, status, error, state) =>
|
||||
{
|
||||
Console.WriteLine("Connected");
|
||||
var tcp2 = new UvTcpHandle(_logger);
|
||||
tcp2.Init(loop);
|
||||
tcp2.Init(loop, (a, b) => { });
|
||||
tcp.Accept(tcp2);
|
||||
var data = Marshal.AllocCoTaskMem(500);
|
||||
tcp2.ReadStart(
|
||||
|
|
@ -140,7 +139,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
null);
|
||||
tcp.Dispose();
|
||||
}, null);
|
||||
Console.WriteLine("Task.Run");
|
||||
var t = Task.Run(async () =>
|
||||
{
|
||||
var socket = new Socket(
|
||||
|
|
@ -179,15 +177,14 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var loop = new UvLoopHandle(_logger);
|
||||
loop.Init(_uv);
|
||||
var tcp = new UvTcpHandle(_logger);
|
||||
tcp.Init(loop);
|
||||
tcp.Init(loop, (a, b) => { });
|
||||
var port = TestServer.GetNextPort();
|
||||
var address = ServerAddress.FromUrl($"http://localhost:{port}/");
|
||||
tcp.Bind(address);
|
||||
tcp.Listen(10, (_, status, error, state) =>
|
||||
{
|
||||
Console.WriteLine("Connected");
|
||||
var tcp2 = new UvTcpHandle(_logger);
|
||||
tcp2.Init(loop);
|
||||
tcp2.Init(loop, (a, b) => { });
|
||||
tcp.Accept(tcp2);
|
||||
var data = Marshal.AllocCoTaskMem(500);
|
||||
tcp2.ReadStart(
|
||||
|
|
@ -227,7 +224,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
null);
|
||||
tcp.Dispose();
|
||||
}, null);
|
||||
Console.WriteLine("Task.Run");
|
||||
var t = Task.Run(async () =>
|
||||
{
|
||||
var socket = new Socket(
|
||||
|
|
@ -268,9 +264,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
#else
|
||||
var count = await socket.ReceiveAsync(new[] { buffer }, SocketFlags.None);
|
||||
#endif
|
||||
Console.WriteLine("count {0} {1}",
|
||||
count,
|
||||
System.Text.Encoding.ASCII.GetString(buffer.Array, 0, count));
|
||||
if (count <= 0) break;
|
||||
}
|
||||
socket.Dispose();
|
||||
|
|
|
|||
Loading…
Reference in New Issue