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
|
||||
{
|
||||
private IntPtr _module = IntPtr.Zero;
|
||||
|
||||
[DllImport("kernel32")]
|
||||
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 Libuv()
|
||||
{
|
||||
IsWindows = PlatformApis.IsWindows();
|
||||
}
|
||||
|
||||
public bool IsWindows;
|
||||
public Func<string, IntPtr> LoadLibrary;
|
||||
public Func<IntPtr, bool> FreeLibrary;
|
||||
public Func<IntPtr, string, IntPtr> GetProcAddress;
|
||||
|
||||
public void Load(string dllToLoad)
|
||||
{
|
||||
PlatformApis.Apply(this);
|
||||
|
||||
var module = LoadLibrary(dllToLoad);
|
||||
foreach (var field in GetType().GetTypeInfo().DeclaredFields)
|
||||
{
|
||||
|
|
@ -78,7 +78,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
public void loop_close(UvLoopHandle handle)
|
||||
{
|
||||
handle.Validate(closed: true);
|
||||
Check(_uv_loop_close(handle.DangerousGetHandle()));
|
||||
Check(_uv_loop_close(handle.InternalGetHandle()));
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
|
|
@ -126,7 +126,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
public void close(UvHandle handle, uv_close_cb close_cb)
|
||||
{
|
||||
handle.Validate(closed: true);
|
||||
_uv_close(handle.DangerousGetHandle(), close_cb);
|
||||
_uv_close(handle.InternalGetHandle(), close_cb);
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
|
|
@ -223,9 +223,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void uv_write_cb(IntPtr req, int status);
|
||||
[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;
|
||||
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();
|
||||
handle.Validate();
|
||||
|
|
@ -244,14 +244,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
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)]
|
||||
delegate IntPtr uv_err_name(int err);
|
||||
uv_err_name _uv_err_name;
|
||||
|
|
@ -270,13 +262,28 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
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)]
|
||||
delegate int uv_req_size(int handleType);
|
||||
uv_req_size _uv_req_size;
|
||||
public int req_size(int handleType)
|
||||
delegate int uv_handle_size(HandleType handleType);
|
||||
uv_handle_size _uv_handle_size;
|
||||
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)]
|
||||
|
|
@ -297,20 +304,84 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
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
|
||||
{
|
||||
long w;
|
||||
long x;
|
||||
long y;
|
||||
long z;
|
||||
long x0;
|
||||
long x1;
|
||||
long x2;
|
||||
long x3;
|
||||
}
|
||||
|
||||
public struct uv_buf_t
|
||||
{
|
||||
public uint len;
|
||||
public IntPtr memory;
|
||||
public uv_buf_t(IntPtr memory, int len, bool IsWindows)
|
||||
{
|
||||
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_tcp;
|
||||
//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)
|
||||
{
|
||||
CreateHandle(loop, 256);
|
||||
CreateHandle(loop, loop.Libuv.handle_size(Libuv.HandleType.ASYNC));
|
||||
_callback = callback;
|
||||
_uv.async_init(loop, this, _uv_async_cb);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
{
|
||||
public void Init(Libuv uv)
|
||||
{
|
||||
CreateHandle(uv, 256);
|
||||
CreateHandle(uv, uv.loop_size());
|
||||
_uv.loop_init(this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
_threadId = loop._threadId;
|
||||
}
|
||||
|
||||
internal IntPtr InternalGetHandle()
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
unsafe protected static void DestroyHandle(IntPtr memory)
|
||||
{
|
||||
var gcHandlePtr = *(IntPtr*)memory;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
{
|
||||
public void Init(UvLoopHandle loop)
|
||||
{
|
||||
CreateHandle(loop, 256);
|
||||
CreateHandle(loop, loop.Libuv.handle_size(Libuv.HandleType.TCP));
|
||||
_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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
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;
|
||||
|
||||
IntPtr _bufs;
|
||||
|
||||
Action<UvWriteReq, int, object> _callback;
|
||||
object _state;
|
||||
const int BUFFER_COUNT = 4;
|
||||
|
||||
List<GCHandle> _pins = new List<GCHandle>();
|
||||
|
||||
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;
|
||||
_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)
|
||||
{
|
||||
var req = FromIntPtr<UvWriteReq>(ptr);
|
||||
foreach(var pin in req._pins)
|
||||
{
|
||||
pin.Free();
|
||||
}
|
||||
req._pins.Clear();
|
||||
req._callback(req, status, req._state);
|
||||
req._callback = null;
|
||||
req._state = null;
|
||||
|
|
|
|||
Loading…
Reference in New Issue