Cross-platform LoadLibrary, adjusting libuv apis
This commit is contained in:
parent
08a3685f53
commit
9c29ccdd32
|
|
@ -10,20 +10,20 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
{
|
{
|
||||||
public class Libuv
|
public class Libuv
|
||||||
{
|
{
|
||||||
private IntPtr _module = IntPtr.Zero;
|
public Libuv()
|
||||||
|
{
|
||||||
[DllImport("kernel32")]
|
IsWindows = PlatformApis.IsWindows();
|
||||||
public static extern IntPtr LoadLibrary(string dllToLoad);
|
}
|
||||||
|
|
||||||
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
|
||||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
|
|
||||||
|
|
||||||
[DllImport("kernel32")]
|
|
||||||
public static extern bool FreeLibrary(IntPtr hModule);
|
|
||||||
|
|
||||||
|
public bool IsWindows;
|
||||||
|
public Func<string, IntPtr> LoadLibrary;
|
||||||
|
public Func<IntPtr, bool> FreeLibrary;
|
||||||
|
public Func<IntPtr, string, IntPtr> GetProcAddress;
|
||||||
|
|
||||||
public void Load(string dllToLoad)
|
public void Load(string dllToLoad)
|
||||||
{
|
{
|
||||||
|
PlatformApis.Apply(this);
|
||||||
|
|
||||||
var module = LoadLibrary(dllToLoad);
|
var module = LoadLibrary(dllToLoad);
|
||||||
foreach (var field in GetType().GetTypeInfo().DeclaredFields)
|
foreach (var field in GetType().GetTypeInfo().DeclaredFields)
|
||||||
{
|
{
|
||||||
|
|
@ -78,7 +78,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
public void loop_close(UvLoopHandle handle)
|
public void loop_close(UvLoopHandle handle)
|
||||||
{
|
{
|
||||||
handle.Validate(closed: true);
|
handle.Validate(closed: true);
|
||||||
Check(_uv_loop_close(handle.DangerousGetHandle()));
|
Check(_uv_loop_close(handle.InternalGetHandle()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
|
@ -126,7 +126,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
public void close(UvHandle handle, uv_close_cb close_cb)
|
public void close(UvHandle handle, uv_close_cb close_cb)
|
||||||
{
|
{
|
||||||
handle.Validate(closed: true);
|
handle.Validate(closed: true);
|
||||||
_uv_close(handle.DangerousGetHandle(), close_cb);
|
_uv_close(handle.InternalGetHandle(), close_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
|
@ -223,9 +223,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
public delegate void uv_write_cb(IntPtr req, int status);
|
public delegate void uv_write_cb(IntPtr req, int status);
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
delegate int uv_write(UvWriteReq req, UvStreamHandle handle, Libuv.uv_buf_t[] bufs, int nbufs, uv_write_cb cb);
|
unsafe delegate int uv_write(UvWriteReq req, UvStreamHandle handle, Libuv.uv_buf_t* bufs, int nbufs, uv_write_cb cb);
|
||||||
uv_write _uv_write;
|
uv_write _uv_write;
|
||||||
public void write(UvWriteReq req, UvStreamHandle handle, Libuv.uv_buf_t[] bufs, int nbufs, uv_write_cb cb)
|
unsafe public void write(UvWriteReq req, UvStreamHandle handle, Libuv.uv_buf_t* bufs, int nbufs, uv_write_cb cb)
|
||||||
{
|
{
|
||||||
req.Validate();
|
req.Validate();
|
||||||
handle.Validate();
|
handle.Validate();
|
||||||
|
|
@ -244,14 +244,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
Check(_uv_shutdown(req, handle, cb));
|
Check(_uv_shutdown(req, handle, cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
delegate int uv_handle_size(int handleType);
|
|
||||||
uv_handle_size _uv_handle_size;
|
|
||||||
public int handle_size(int handleType)
|
|
||||||
{
|
|
||||||
return _uv_handle_size(handleType);
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
delegate IntPtr uv_err_name(int err);
|
delegate IntPtr uv_err_name(int err);
|
||||||
uv_err_name _uv_err_name;
|
uv_err_name _uv_err_name;
|
||||||
|
|
@ -270,13 +262,28 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
return ptr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(ptr);
|
return ptr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_loop_size();
|
||||||
|
uv_loop_size _uv_loop_size;
|
||||||
|
public int loop_size()
|
||||||
|
{
|
||||||
|
return _uv_loop_size();
|
||||||
|
}
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
delegate int uv_req_size(int handleType);
|
delegate int uv_handle_size(HandleType handleType);
|
||||||
uv_req_size _uv_req_size;
|
uv_handle_size _uv_handle_size;
|
||||||
public int req_size(int handleType)
|
public int handle_size(HandleType handleType)
|
||||||
{
|
{
|
||||||
return _uv_req_size(handleType);
|
return _uv_handle_size(handleType);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_req_size(RequestType reqType);
|
||||||
|
uv_req_size _uv_req_size;
|
||||||
|
public int req_size(RequestType reqType)
|
||||||
|
{
|
||||||
|
return _uv_req_size(reqType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
|
@ -297,20 +304,84 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
return Check(_uv_ip6_addr(ip, port, out addr), out error);
|
return Check(_uv_ip6_addr(ip, port, out addr), out error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void uv_walk_cb(IntPtr handle, IntPtr arg);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
unsafe delegate int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg);
|
||||||
|
uv_walk _uv_walk;
|
||||||
|
unsafe public void walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg)
|
||||||
|
{
|
||||||
|
loop.Validate();
|
||||||
|
_uv_walk(loop, walk_cb, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uv_buf_t buf_init(IntPtr memory, int len)
|
||||||
|
{
|
||||||
|
return new uv_buf_t(memory, len, IsWindows);
|
||||||
|
}
|
||||||
|
|
||||||
public struct sockaddr
|
public struct sockaddr
|
||||||
{
|
{
|
||||||
long w;
|
long x0;
|
||||||
long x;
|
long x1;
|
||||||
long y;
|
long x2;
|
||||||
long z;
|
long x3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct uv_buf_t
|
public struct uv_buf_t
|
||||||
{
|
{
|
||||||
public uint len;
|
public uv_buf_t(IntPtr memory, int len, bool IsWindows)
|
||||||
public IntPtr memory;
|
{
|
||||||
|
if (IsWindows)
|
||||||
|
{
|
||||||
|
x0 = (IntPtr)len;
|
||||||
|
x1 = memory;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x0 = memory;
|
||||||
|
x1 = (IntPtr)len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr x0;
|
||||||
|
public IntPtr x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum HandleType
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
ASYNC,
|
||||||
|
CHECK,
|
||||||
|
FS_EVENT,
|
||||||
|
FS_POLL,
|
||||||
|
HANDLE,
|
||||||
|
IDLE,
|
||||||
|
NAMED_PIPE,
|
||||||
|
POLL,
|
||||||
|
PREPARE,
|
||||||
|
PROCESS,
|
||||||
|
STREAM,
|
||||||
|
TCP,
|
||||||
|
TIMER,
|
||||||
|
TTY,
|
||||||
|
UDP,
|
||||||
|
SIGNAL,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum RequestType
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
REQ,
|
||||||
|
CONNECT,
|
||||||
|
WRITE,
|
||||||
|
SHUTDOWN,
|
||||||
|
UDP_SEND,
|
||||||
|
FS,
|
||||||
|
WORK,
|
||||||
|
GETADDRINFO,
|
||||||
|
GETNAMEINFO,
|
||||||
|
}
|
||||||
//int handle_size_async;
|
//int handle_size_async;
|
||||||
//int handle_size_tcp;
|
//int handle_size_tcp;
|
||||||
//int req_size_write;
|
//int req_size_write;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
|
{
|
||||||
|
public static class PlatformApis
|
||||||
|
{
|
||||||
|
public static bool IsWindows()
|
||||||
|
{
|
||||||
|
var p = (int)Environment.OSVersion.Platform;
|
||||||
|
return (p != 4) && (p != 6) && (p != 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Apply(Libuv libuv)
|
||||||
|
{
|
||||||
|
if (libuv.IsWindows)
|
||||||
|
{
|
||||||
|
WindowsApis.Apply(libuv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LinuxApis.Apply(libuv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WindowsApis
|
||||||
|
{
|
||||||
|
[DllImport("kernel32")]
|
||||||
|
public static extern IntPtr LoadLibrary(string dllToLoad);
|
||||||
|
|
||||||
|
[DllImport("kernel32")]
|
||||||
|
public static extern bool FreeLibrary(IntPtr hModule);
|
||||||
|
|
||||||
|
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||||
|
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
|
||||||
|
|
||||||
|
public static void Apply(Libuv libuv)
|
||||||
|
{
|
||||||
|
libuv.LoadLibrary = LoadLibrary;
|
||||||
|
libuv.FreeLibrary = FreeLibrary;
|
||||||
|
libuv.GetProcAddress = GetProcAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LinuxApis
|
||||||
|
{
|
||||||
|
[DllImport("libdl")]
|
||||||
|
public static extern IntPtr dlopen(String fileName, int flags);
|
||||||
|
|
||||||
|
[DllImport("libdl")]
|
||||||
|
public static extern IntPtr dlsym(IntPtr handle, String symbol);
|
||||||
|
|
||||||
|
[DllImport("libdl")]
|
||||||
|
public static extern int dlclose(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport("libdl")]
|
||||||
|
public static extern IntPtr dlerror();
|
||||||
|
|
||||||
|
public static IntPtr LoadLibrary(string dllToLoad)
|
||||||
|
{
|
||||||
|
return dlopen(dllToLoad, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool FreeLibrary(IntPtr hModule)
|
||||||
|
{
|
||||||
|
return dlclose(hModule) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntPtr GetProcAddress(IntPtr hModule, string procedureName)
|
||||||
|
{
|
||||||
|
dlerror();
|
||||||
|
var res = dlsym(hModule, procedureName);
|
||||||
|
var errPtr = dlerror();
|
||||||
|
return errPtr == IntPtr.Zero ? res : IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Apply(Libuv libuv)
|
||||||
|
{
|
||||||
|
libuv.LoadLibrary = LoadLibrary;
|
||||||
|
libuv.FreeLibrary = FreeLibrary;
|
||||||
|
libuv.GetProcAddress = GetProcAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
|
|
||||||
public void Init(UvLoopHandle loop, Action callback)
|
public void Init(UvLoopHandle loop, Action callback)
|
||||||
{
|
{
|
||||||
CreateHandle(loop, 256);
|
CreateHandle(loop, loop.Libuv.handle_size(Libuv.HandleType.ASYNC));
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
_uv.async_init(loop, this, _uv_async_cb);
|
_uv.async_init(loop, this, _uv_async_cb);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
{
|
{
|
||||||
public void Init(Libuv uv)
|
public void Init(Libuv uv)
|
||||||
{
|
{
|
||||||
CreateHandle(uv, 256);
|
CreateHandle(uv, uv.loop_size());
|
||||||
_uv.loop_init(this);
|
_uv.loop_init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
_threadId = loop._threadId;
|
_threadId = loop._threadId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal IntPtr InternalGetHandle()
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
public void Validate(bool closed = false)
|
public void Validate(bool closed = false)
|
||||||
{
|
{
|
||||||
|
|
@ -53,7 +57,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
Trace.Assert(_threadId == Thread.CurrentThread.ManagedThreadId, "ThreadId is correct");
|
Trace.Assert(_threadId == Thread.CurrentThread.ManagedThreadId, "ThreadId is correct");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsafe protected static void DestroyHandle(IntPtr memory)
|
unsafe protected static void DestroyHandle(IntPtr memory)
|
||||||
{
|
{
|
||||||
var gcHandlePtr = *(IntPtr*)memory;
|
var gcHandlePtr = *(IntPtr*)memory;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
|
|
||||||
public void Init(UvLoopHandle loop)
|
public void Init(UvLoopHandle loop)
|
||||||
{
|
{
|
||||||
CreateHandle(loop, loop.Libuv.req_size(3));
|
CreateHandle(loop, loop.Libuv.req_size(Libuv.RequestType.SHUTDOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Shutdown(UvStreamHandle handle, Action<UvShutdownReq, int, object> callback, object state)
|
public void Shutdown(UvStreamHandle handle, Action<UvShutdownReq, int, object> callback, object state)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
{
|
{
|
||||||
public void Init(UvLoopHandle loop)
|
public void Init(UvLoopHandle loop)
|
||||||
{
|
{
|
||||||
CreateHandle(loop, 256);
|
CreateHandle(loop, loop.Libuv.handle_size(Libuv.HandleType.TCP));
|
||||||
_uv.tcp_init(loop, this);
|
_uv.tcp_init(loop, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
|
|
@ -13,24 +14,56 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
{
|
{
|
||||||
private readonly static Libuv.uv_write_cb _uv_write_cb = UvWriteCb;
|
private readonly static Libuv.uv_write_cb _uv_write_cb = UvWriteCb;
|
||||||
|
|
||||||
|
IntPtr _bufs;
|
||||||
|
|
||||||
Action<UvWriteReq, int, object> _callback;
|
Action<UvWriteReq, int, object> _callback;
|
||||||
object _state;
|
object _state;
|
||||||
|
const int BUFFER_COUNT = 4;
|
||||||
|
|
||||||
|
List<GCHandle> _pins = new List<GCHandle>();
|
||||||
|
|
||||||
public void Init(UvLoopHandle loop)
|
public void Init(UvLoopHandle loop)
|
||||||
{
|
{
|
||||||
CreateHandle(loop, loop.Libuv.req_size(2));
|
var requestSize = loop.Libuv.req_size(Libuv.RequestType.WRITE);
|
||||||
|
var bufferSize = Marshal.SizeOf(typeof(Libuv.uv_buf_t)) * BUFFER_COUNT;
|
||||||
|
CreateHandle(loop, requestSize + bufferSize);
|
||||||
|
_bufs = handle + requestSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(UvStreamHandle handle, Libuv.uv_buf_t[] bufs, int nbufs, Action<UvWriteReq, int, object> callback, object state)
|
public unsafe void Write(UvStreamHandle handle, ArraySegment<ArraySegment<byte>> bufs, Action<UvWriteReq, int, object> callback, object state)
|
||||||
{
|
{
|
||||||
|
var pBuffers = (Libuv.uv_buf_t*)_bufs;
|
||||||
|
var nBuffers = bufs.Count;
|
||||||
|
if (nBuffers > BUFFER_COUNT)
|
||||||
|
{
|
||||||
|
var bufArray = new Libuv.uv_buf_t[nBuffers];
|
||||||
|
var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned);
|
||||||
|
_pins.Add(gcHandle);
|
||||||
|
pBuffers = (Libuv.uv_buf_t*)gcHandle.AddrOfPinnedObject();
|
||||||
|
}
|
||||||
|
for (var index = 0; index != nBuffers; ++index)
|
||||||
|
{
|
||||||
|
var buf = bufs.Array[bufs.Offset + index];
|
||||||
|
|
||||||
|
var gcHandle = GCHandle.Alloc(buf.Array, GCHandleType.Pinned);
|
||||||
|
_pins.Add(gcHandle);
|
||||||
|
pBuffers[index] = Libuv.buf_init(
|
||||||
|
gcHandle.AddrOfPinnedObject() + buf.Offset,
|
||||||
|
buf.Count);
|
||||||
|
}
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
_state = state;
|
_state = state;
|
||||||
_uv.write(this, handle, bufs, nbufs, _uv_write_cb);
|
_uv.write(this, handle, pBuffers, nBuffers, _uv_write_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UvWriteCb(IntPtr ptr, int status)
|
private static void UvWriteCb(IntPtr ptr, int status)
|
||||||
{
|
{
|
||||||
var req = FromIntPtr<UvWriteReq>(ptr);
|
var req = FromIntPtr<UvWriteReq>(ptr);
|
||||||
|
foreach(var pin in req._pins)
|
||||||
|
{
|
||||||
|
pin.Free();
|
||||||
|
}
|
||||||
|
req._pins.Clear();
|
||||||
req._callback(req, status, req._state);
|
req._callback(req, status, req._state);
|
||||||
req._callback = null;
|
req._callback = null;
|
||||||
req._state = null;
|
req._state = null;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue