From 309dbe3be0c74769e47f7e6fdec0dbdee3725ba2 Mon Sep 17 00:00:00 2001 From: Steve Hawley Date: Fri, 10 Feb 2023 19:06:29 -0500 Subject: [PATCH] [DotNet] CoreFoundation Pinvokes (#17505) Updates the pinvokes in CoreFoundation to have blittable types. I intentionally did *not* do `CFReadStream` and `CFWriteStream` as the changes needed for those are may create a breaking API change, so those should probably be their own PR for closer scrutiny. Please look closely at CFProxySupport as that was the least straightforward of the changes. --- src/CoreFoundation/CFMessagePort.cs | 67 ++++++++++++ src/CoreFoundation/CFNotificationCenter.cs | 24 +++++ src/CoreFoundation/CFProxySupport.cs | 84 +++++++++++++++ src/CoreFoundation/CFSocket.cs | 49 +++++++++ src/CoreFoundation/Dispatch.cs | 118 ++++++++++++++++++++- src/CoreFoundation/OSLog.cs | 12 ++- tests/cecil-tests/BlittablePInvokes.cs | 2 +- 7 files changed, 350 insertions(+), 6 deletions(-) diff --git a/src/CoreFoundation/CFMessagePort.cs b/src/CoreFoundation/CFMessagePort.cs index fb6bd356fb1..24047d11350 100644 --- a/src/CoreFoundation/CFMessagePort.cs +++ b/src/CoreFoundation/CFMessagePort.cs @@ -55,20 +55,31 @@ public class CFMessagePort : NativeObject { // CFMessagePortContext [StructLayout (LayoutKind.Sequential)] +#if NET + unsafe +#endif struct ContextProxy { /* CFIndex */ nint version; // must be 0 public /* void * */ IntPtr info; +#if NET + public delegate* unmanaged retain; + public delegate* unmanaged release; + public delegate* unmanaged copyDescription; +#else public /* CFAllocatorRetainCallBack*/ Func retain; public /* CFAllocatorReleaseCallBack*/ Action release; public /* CFAllocatorCopyDescriptionCallBack*/ Func copyDescription; +#endif } public delegate NSData CFMessagePortCallBack (int type, NSData data); +#if !NET delegate /* CFDataRef */ IntPtr CFMessagePortCallBackProxy (/* CFMessagePortRef */ IntPtr messagePort, /* SInt32 */ int type, /* CFDataRef */ IntPtr data, /* void* */ IntPtr info); delegate void CFMessagePortInvalidationCallBackProxy (/* CFMessagePortRef */ IntPtr messagePort, /* void * */ IntPtr info); +#endif static Dictionary outputHandles = new Dictionary (Runtime.IntPtrEqualityComparer); @@ -76,9 +87,11 @@ struct ContextProxy { static Dictionary messagePortContexts = new Dictionary (Runtime.IntPtrEqualityComparer); +#if !NET static CFMessagePortCallBackProxy messageOutputCallback = new CFMessagePortCallBackProxy (MessagePortCallback); static CFMessagePortInvalidationCallBackProxy messageInvalidationCallback = new CFMessagePortInvalidationCallBackProxy (MessagePortInvalidationCallback); +#endif IntPtr contextHandle; @@ -139,7 +152,13 @@ public Action? InvalidationCallback { invalidationHandles.Add (GetCheckedHandle (), value); } +#if NET + unsafe { + CFMessagePortSetInvalidationCallBack (Handle, &MessagePortInvalidationCallback); + } +#else CFMessagePortSetInvalidationCallBack (Handle, messageInvalidationCallback); +#endif } } @@ -172,8 +191,13 @@ protected override void Dispose (bool disposing) base.Dispose (disposing); } +#if NET + [DllImport (Constants.CoreFoundationLibrary)] + static unsafe extern /* CFMessagePortRef */ IntPtr CFMessagePortCreateLocal (/* CFAllocatorRef */ IntPtr allocator, /* CFStringRef */ IntPtr name, delegate* unmanaged callout, /* CFMessagePortContext */ ContextProxy* context, [MarshalAs (UnmanagedType.I1)] bool* shouldFreeInfo); +#else [DllImport (Constants.CoreFoundationLibrary)] static extern /* CFMessagePortRef */ IntPtr CFMessagePortCreateLocal (/* CFAllocatorRef */ IntPtr allocator, /* CFStringRef */ IntPtr name, CFMessagePortCallBackProxy callout, /* CFMessagePortContext */ ref ContextProxy context, [MarshalAs (UnmanagedType.I1)] ref bool shouldFreeInfo); +#endif [DllImport (Constants.CoreFoundationLibrary)] static extern /* CFMessagePortRef */ IntPtr CFMessagePortCreateRemote (/* CFAllocatorRef */ IntPtr allocator, /* CFStringRef */ IntPtr name); @@ -208,8 +232,13 @@ protected override void Dispose (bool disposing) [DllImport (Constants.CoreFoundationLibrary)] static extern void CFMessagePortSetDispatchQueue (/* CFMessagePortRef */ IntPtr ms, dispatch_queue_t queue); +#if NET + [DllImport (Constants.CoreFoundationLibrary)] + static unsafe extern void CFMessagePortSetInvalidationCallBack (/* CFMessagePortRef */ IntPtr ms, delegate* unmanaged callout); +#else [DllImport (Constants.CoreFoundationLibrary)] static extern void CFMessagePortSetInvalidationCallBack (/* CFMessagePortRef */ IntPtr ms, CFMessagePortInvalidationCallBackProxy callout); +#endif [DllImport (Constants.CoreFoundationLibrary)] static extern IntPtr CFMessagePortGetInvalidationCallBack (/* CFMessagePortRef */ IntPtr ms); @@ -234,19 +263,37 @@ protected override void Dispose (bool disposing) var shortHandle = GCHandle.Alloc (contextProxy); if (context is not null) { +#if NET + unsafe { + if (context.Retain is not null) + contextProxy.retain = &RetainProxy; + if (context.Release is not null) + contextProxy.release = &ReleaseProxy; + if (context.CopyDescription is not null) + contextProxy.copyDescription = &CopyDescriptionProxy; + } +#else if (context.Retain is not null) contextProxy.retain = RetainProxy; if (context.Release is not null) contextProxy.release = ReleaseProxy; if (context.CopyDescription is not null) contextProxy.copyDescription = CopyDescriptionProxy; +#endif contextProxy.info = (IntPtr) shortHandle; lock (messagePortContexts) messagePortContexts.Add (contextProxy.info, context); } try { +#if NET + IntPtr portHandle; + unsafe { + portHandle = CFMessagePortCreateLocal (allocator.GetHandle (), n, &MessagePortCallback, &contextProxy, &shouldFreeInfo); + } +#else var portHandle = CFMessagePortCreateLocal (allocator.GetHandle (), n, messageOutputCallback, ref contextProxy, ref shouldFreeInfo); +#endif // TODO handle should free info if (portHandle == IntPtr.Zero) @@ -279,7 +326,11 @@ protected override void Dispose (bool disposing) // // Proxy callbacks // +#if NET + [UnmanagedCallersOnly] +#else [MonoPInvokeCallback (typeof (Func))] +#endif static IntPtr RetainProxy (IntPtr info) { INativeObject? result = null; @@ -295,7 +346,11 @@ static IntPtr RetainProxy (IntPtr info) return result.GetHandle (); } +#if NET + [UnmanagedCallersOnly] +#else [MonoPInvokeCallback (typeof (Action))] +#endif static void ReleaseProxy (IntPtr info) { CFMessagePortContext? context; @@ -307,7 +362,11 @@ static void ReleaseProxy (IntPtr info) context.Release (); } +#if NET + [UnmanagedCallersOnly] +#else [MonoPInvokeCallback (typeof (Func))] +#endif static IntPtr CopyDescriptionProxy (IntPtr info) { NSString? result = null; @@ -322,7 +381,11 @@ static IntPtr CopyDescriptionProxy (IntPtr info) return result.GetHandle (); } +#if NET + [UnmanagedCallersOnly] +#else [MonoPInvokeCallback (typeof (CFMessagePortCallBackProxy))] +#endif static IntPtr MessagePortCallback (IntPtr local, int msgid, IntPtr data, IntPtr info) { CFMessagePortCallBack callback; @@ -341,7 +404,11 @@ static IntPtr MessagePortCallback (IntPtr local, int msgid, IntPtr data, IntPtr } } +#if NET + [UnmanagedCallersOnly] +#else [MonoPInvokeCallback (typeof (CFMessagePortInvalidationCallBackProxy))] +#endif static void MessagePortInvalidationCallback (IntPtr messagePort, IntPtr info) { Action? callback; diff --git a/src/CoreFoundation/CFNotificationCenter.cs b/src/CoreFoundation/CFNotificationCenter.cs index b49129fb585..7d03e884af2 100644 --- a/src/CoreFoundation/CFNotificationCenter.cs +++ b/src/CoreFoundation/CFNotificationCenter.cs @@ -126,12 +126,23 @@ public CFNotificationObserverToken AddObserver (string name, INativeObject objec lock (listeners) { if (!listeners.TryGetValue (name, out listenersForName)) { listenersForName = new List (1); +#if NET + unsafe { + CFNotificationCenterAddObserver (center: Handle, + observer: Handle, + callback: &NotificationCallback, + name: strHandle, + obj: token.observedObject, + suspensionBehavior: (IntPtr) suspensionBehavior); + } +#else CFNotificationCenterAddObserver (center: Handle, observer: Handle, callback: NotificationCallback, name: strHandle, obj: token.observedObject, suspensionBehavior: (IntPtr) suspensionBehavior); +#endif } else listenersForName = new List (listenersForName); listenersForName.Add (token); @@ -163,9 +174,15 @@ void notification (string? name, NSDictionary? userInfo) } } +#if !NET delegate void CFNotificationCallback (CFNotificationCenterRef center, IntPtr observer, IntPtr name, IntPtr obj, IntPtr userInfo); +#endif +#if NET + [UnmanagedCallersOnly] +#else [MonoPInvokeCallback (typeof (CFNotificationCallback))] +#endif static void NotificationCallback (CFNotificationCenterRef centerPtr, IntPtr observer, IntPtr name, IntPtr obj, IntPtr userInfo) { CFNotificationCenter center; @@ -245,10 +262,17 @@ public void RemoveEveryObserver () } +#if NET + [DllImport (Constants.CoreFoundationLibrary)] + static extern unsafe void CFNotificationCenterAddObserver (CFNotificationCenterRef center, IntPtr observer, + delegate* unmanaged callback, IntPtr name, IntPtr obj, + /* CFNotificationSuspensionBehavior */ IntPtr suspensionBehavior); +#else [DllImport (Constants.CoreFoundationLibrary)] static extern unsafe void CFNotificationCenterAddObserver (CFNotificationCenterRef center, IntPtr observer, CFNotificationCallback callback, IntPtr name, IntPtr obj, /* CFNotificationSuspensionBehavior */ IntPtr suspensionBehavior); +#endif [DllImport (Constants.CoreFoundationLibrary)] static extern unsafe void CFNotificationCenterPostNotificationWithOptions (CFNotificationCenterRef center, IntPtr name, IntPtr obj, IntPtr userInfo, int options); diff --git a/src/CoreFoundation/CFProxySupport.cs b/src/CoreFoundation/CFProxySupport.cs index 9018a932b9d..a62e0cefd36 100644 --- a/src/CoreFoundation/CFProxySupport.cs +++ b/src/CoreFoundation/CFProxySupport.cs @@ -615,9 +615,15 @@ public static partial class CFNetwork { return new CFProxySettings (dict); } +#if !NET delegate void CFProxyAutoConfigurationResultCallbackInternal (IntPtr client, IntPtr proxyList, IntPtr error); // helper delegate to reuse code +#endif +#if NET + unsafe delegate IntPtr CreatePACCFRunLoopSource (delegate* unmanaged cb, ref CFStreamClientContext context); +#else delegate IntPtr CreatePACCFRunLoopSource (CFProxyAutoConfigurationResultCallbackInternal cb, ref CFStreamClientContext context); +#endif static CFProxy []? ParseProxies (IntPtr proxyList) { @@ -659,7 +665,11 @@ public NSError? Error { } // callback that will sent the client info +#if NET + [UnmanagedCallersOnly] +#else [MonoPInvokeCallback (typeof (CFProxyAutoConfigurationResultCallbackInternal))] +#endif static void ExecutePacCallback (IntPtr client, IntPtr proxyList, IntPtr error) { // grab the required structure and set the data, according apple docs: @@ -705,7 +715,12 @@ await Task.Run (() => { var clientContext = new CFStreamClientContext (); clientContext.Info = pacDataPtr; +#if NET + unsafe { + using (var loopSource = new CFRunLoopSource (factory (&ExecutePacCallback, ref clientContext), false)) +#else using (var loopSource = new CFRunLoopSource (factory (ExecutePacCallback, ref clientContext), false)) +#endif using (var mode = new NSString ("Xamarin.iOS.Proxy")) { if (cancellationToken.IsCancellationRequested) @@ -723,6 +738,9 @@ await Task.Run (() => { // does not raise an error if source is not longer present, so no need to worry runLoop.RemoveSource (loopSource, mode); } +#if NET + } // matches the unsafe block +#endif if (cancellationToken.IsCancellationRequested) throw new OperationCanceledException ("Operation was cancelled."); @@ -761,7 +779,12 @@ await Task.Run (() => { var clientContext = new CFStreamClientContext (); clientContext.Info = pacDataPtr; +#if NET + unsafe { + using (var loopSource = new CFRunLoopSource (factory (&ExecutePacCallback, ref clientContext), false)) +#else using (var loopSource = new CFRunLoopSource (factory (ExecutePacCallback, ref clientContext), false)) +#endif using (var mode = new NSString ("Xamarin.iOS.Proxy")) { runLoop.AddSource (loopSource, mode); runLoop.RunInMode (mode, double.MaxValue, false); @@ -770,6 +793,9 @@ await Task.Run (() => { pacCbData = (PACProxyCallbackData) Marshal.PtrToStructure (pacDataPtr, typeof (PACProxyCallbackData))!; // get data from the struct outError = pacCbData.Error; +#if NET + } // unsafe +#endif return pacCbData.ProxyList; } finally { if (pacCbData.ProxyListPtr != IntPtr.Zero) @@ -780,12 +806,21 @@ await Task.Run (() => { } } +#if NET + [DllImport (Constants.CFNetworkLibrary)] + extern unsafe static /* CFRunLoopSourceRef __nonnull */ IntPtr CFNetworkExecuteProxyAutoConfigurationScript ( + /* CFStringRef __nonnull */ IntPtr proxyAutoConfigurationScript, + /* CFURLRef __nonnull */ IntPtr targetURL, + /* CFProxyAutoConfigurationResultCallback __nonnull */ delegate* unmanaged cb, + /* CFStreamClientContext * __nonnull */ ref CFStreamClientContext clientContext); +#else [DllImport (Constants.CFNetworkLibrary)] extern static /* CFRunLoopSourceRef __nonnull */ IntPtr CFNetworkExecuteProxyAutoConfigurationScript ( /* CFStringRef __nonnull */ IntPtr proxyAutoConfigurationScript, /* CFURLRef __nonnull */ IntPtr targetURL, /* CFProxyAutoConfigurationResultCallback __nonnull */ CFProxyAutoConfigurationResultCallbackInternal cb, /* CFStreamClientContext * __nonnull */ ref CFStreamClientContext clientContext); +#endif public static CFProxy []? ExecuteProxyAutoConfigurationScript (string proxyAutoConfigurationScript, Uri targetUrl, out NSError? outError) { @@ -798,10 +833,20 @@ await Task.Run (() => { using (var pacScript = new NSString (proxyAutoConfigurationScript)) using (var url = new NSUrl (targetUrl.AbsoluteUri)) { +#if NET + CreatePACCFRunLoopSource factory; + unsafe { + factory = delegate (delegate* unmanaged cb, ref CFStreamClientContext context) + { + return CFNetworkExecuteProxyAutoConfigurationScript (pacScript.Handle, url.Handle, cb, ref context); + }; + } +#else CreatePACCFRunLoopSource factory = delegate (CFProxyAutoConfigurationResultCallbackInternal cb, ref CFStreamClientContext context) { return CFNetworkExecuteProxyAutoConfigurationScript (pacScript.Handle, url.Handle, cb, ref context); }; +#endif return ExecutePacCFRunLoopSourceBlocking (factory, out outError); } } @@ -816,21 +861,40 @@ await Task.Run (() => { using (var pacScript = new NSString (proxyAutoConfigurationScript)) using (var url = new NSUrl (targetUrl.AbsoluteUri)) { +#if NET + CreatePACCFRunLoopSource factory; + unsafe { + factory = delegate (delegate* unmanaged cb, ref CFStreamClientContext context) + { + return CFNetworkExecuteProxyAutoConfigurationScript (pacScript.Handle, url.Handle, cb, ref context); + }; + } +#else CreatePACCFRunLoopSource factory = delegate (CFProxyAutoConfigurationResultCallbackInternal cb, ref CFStreamClientContext context) { return CFNetworkExecuteProxyAutoConfigurationScript (pacScript.Handle, url.Handle, cb, ref context); }; +#endif // use the helper task with a factory for this method return await ExecutePacCFRunLoopSourceAsync (factory, cancellationToken).ConfigureAwait (false); } } +#if NET + [DllImport (Constants.CFNetworkLibrary)] + extern unsafe static /* CFRunLoopSourceRef __nonnull */ IntPtr CFNetworkExecuteProxyAutoConfigurationURL ( + /* CFURLRef __nonnull */ IntPtr proxyAutoConfigurationURL, + /* CFURLRef __nonnull */ IntPtr targetURL, + /* CFProxyAutoConfigurationResultCallback __nonnull */ delegate* unmanaged cb, + /* CFStreamClientContext * __nonnull */ ref CFStreamClientContext clientContext); +#else [DllImport (Constants.CFNetworkLibrary)] extern static /* CFRunLoopSourceRef __nonnull */ IntPtr CFNetworkExecuteProxyAutoConfigurationURL ( /* CFURLRef __nonnull */ IntPtr proxyAutoConfigurationURL, /* CFURLRef __nonnull */ IntPtr targetURL, /* CFProxyAutoConfigurationResultCallback __nonnull */ CFProxyAutoConfigurationResultCallbackInternal cb, /* CFStreamClientContext * __nonnull */ ref CFStreamClientContext clientContext); +#endif public static CFProxy []? ExecuteProxyAutoConfigurationUrl (Uri proxyAutoConfigurationUrl, Uri targetUrl, out NSError? outError) { @@ -843,10 +907,20 @@ await Task.Run (() => { using (var pacUrl = new NSUrl (proxyAutoConfigurationUrl.AbsoluteUri)) // toll free bridge to CFUrl using (var url = new NSUrl (targetUrl.AbsoluteUri)) { +#if NET + CreatePACCFRunLoopSource factory; + unsafe { + factory = delegate (delegate* unmanaged cb, ref CFStreamClientContext context) + { + return CFNetworkExecuteProxyAutoConfigurationURL (pacUrl.Handle, url.Handle, cb, ref context); + }; + } +#else CreatePACCFRunLoopSource factory = delegate (CFProxyAutoConfigurationResultCallbackInternal cb, ref CFStreamClientContext context) { return CFNetworkExecuteProxyAutoConfigurationURL (pacUrl.Handle, url.Handle, cb, ref context); }; +#endif return ExecutePacCFRunLoopSourceBlocking (factory, out outError); } } @@ -862,10 +936,20 @@ await Task.Run (() => { using (var pacUrl = new NSUrl (proxyAutoConfigurationUrl.AbsoluteUri)) // toll free bridge to CFUrl using (var url = new NSUrl (targetUrl.AbsoluteUri)) { +#if NET + CreatePACCFRunLoopSource factory; + unsafe { + factory = delegate (delegate* unmanaged cb, ref CFStreamClientContext context) + { + return CFNetworkExecuteProxyAutoConfigurationURL (pacUrl.Handle, url.Handle, cb, ref context); + }; + } +#else CreatePACCFRunLoopSource factory = delegate (CFProxyAutoConfigurationResultCallbackInternal cb, ref CFStreamClientContext context) { return CFNetworkExecuteProxyAutoConfigurationURL (pacUrl.Handle, url.Handle, cb, ref context); }; +#endif // use the helper task with a factory for this method return await ExecutePacCFRunLoopSourceAsync (factory, cancellationToken).ConfigureAwait (false); } diff --git a/src/CoreFoundation/CFSocket.cs b/src/CoreFoundation/CFSocket.cs index 3e02a3194bf..32144b6eed8 100644 --- a/src/CoreFoundation/CFSocket.cs +++ b/src/CoreFoundation/CFSocket.cs @@ -326,9 +326,15 @@ protected override void Dispose (bool disposing) base.Dispose (disposing); } +#if !NET delegate void CFSocketCallBack (IntPtr s, nuint type, IntPtr address, IntPtr data, IntPtr info); +#endif +#if NET + [UnmanagedCallersOnly] +#else [MonoPInvokeCallback (typeof (CFSocketCallBack))] +#endif static void OnCallback (IntPtr s, nuint type, IntPtr address, IntPtr data, IntPtr info) { var socket = GCHandle.FromIntPtr (info).Target as CFSocket; @@ -366,15 +372,29 @@ static void OnCallback (IntPtr s, nuint type, IntPtr address, IntPtr data, IntPt } } +#if NET + [DllImport (Constants.CoreFoundationLibrary)] + unsafe extern static IntPtr CFSocketCreate (IntPtr allocator, int /*SInt32*/ family, int /*SInt32*/ type, int /*SInt32*/ proto, + nuint /*CFOptionFlags*/ callBackTypes, + delegate* unmanaged callout, CFSocketContext* ctx); +#else [DllImport (Constants.CoreFoundationLibrary)] unsafe extern static IntPtr CFSocketCreate (IntPtr allocator, int /*SInt32*/ family, int /*SInt32*/ type, int /*SInt32*/ proto, nuint /*CFOptionFlags*/ callBackTypes, CFSocketCallBack callout, CFSocketContext* ctx); +#endif +#if NET + [DllImport (Constants.CoreFoundationLibrary)] + unsafe extern static IntPtr CFSocketCreateWithNative (IntPtr allocator, CFSocketNativeHandle sock, + nuint /*CFOptionFlags*/ callBackTypes, + delegate* unmanaged callout, CFSocketContext* ctx); +#else [DllImport (Constants.CoreFoundationLibrary)] unsafe extern static IntPtr CFSocketCreateWithNative (IntPtr allocator, CFSocketNativeHandle sock, nuint /*CFOptionFlags*/ callBackTypes, CFSocketCallBack callout, CFSocketContext* ctx); +#endif [DllImport (Constants.CoreFoundationLibrary)] extern static IntPtr CFSocketCreateRunLoopSource (IntPtr allocator, IntPtr socket, nint order); @@ -402,30 +422,51 @@ public CFSocket (AddressFamily family, SocketType type, ProtocolType proto, CFRu CFSocket (int family, int type, int proto, CFRunLoop loop) { unsafe { +#if NET + Initialize ( + loop, + (CFSocketContext* ctx) => CFSocketCreate (IntPtr.Zero, family, type, proto, (nuint) (ulong) defaultCallbackTypes, &OnCallback, ctx) + ); +#else Initialize ( loop, (CFSocketContext* ctx) => CFSocketCreate (IntPtr.Zero, family, type, proto, (nuint) (ulong) defaultCallbackTypes, OnCallback, ctx) ); +#endif } } CFSocket (CFSocketNativeHandle sock) { unsafe { +#if NET + Initialize ( + CFRunLoop.Current, + (CFSocketContext* ctx) => CFSocketCreateWithNative (IntPtr.Zero, sock, (nuint) (ulong) defaultCallbackTypes, &OnCallback, ctx) + ); +#else Initialize ( CFRunLoop.Current, (CFSocketContext* ctx) => CFSocketCreateWithNative (IntPtr.Zero, sock, (nuint) (ulong) defaultCallbackTypes, OnCallback, ctx) ); +#endif } } internal CFSocket (CFSocketSignature sig, double timeout) { unsafe { +#if NET + Initialize ( + CFRunLoop.Current, + (CFSocketContext* ctx) => CFSocketCreateConnectedToSocketSignature (IntPtr.Zero, ref sig, (nuint) (ulong) defaultCallbackTypes, &OnCallback, ctx, timeout) + ); +#else Initialize ( CFRunLoop.Current, (CFSocketContext* ctx) => CFSocketCreateConnectedToSocketSignature (IntPtr.Zero, ref sig, (nuint) (ulong) defaultCallbackTypes, OnCallback, ctx, timeout) ); +#endif } } @@ -453,11 +494,19 @@ void Initialize (CFRunLoop runLoop, CreateSocket createSocket) } } +#if NET + [DllImport (Constants.CoreFoundationLibrary)] + unsafe extern static IntPtr CFSocketCreateConnectedToSocketSignature (IntPtr allocator, ref CFSocketSignature signature, + nuint /*CFOptionFlags*/ callBackTypes, + delegate* unmanaged callout, + CFSocketContext* context, double timeout); +#else [DllImport (Constants.CoreFoundationLibrary)] unsafe extern static IntPtr CFSocketCreateConnectedToSocketSignature (IntPtr allocator, ref CFSocketSignature signature, nuint /*CFOptionFlags*/ callBackTypes, CFSocketCallBack callout, CFSocketContext* context, double timeout); +#endif public static CFSocket CreateConnectedToSocketSignature (AddressFamily family, SocketType type, ProtocolType proto, IPEndPoint endpoint, diff --git a/src/CoreFoundation/Dispatch.cs b/src/CoreFoundation/Dispatch.cs index 4c242543d01..203d3f16caf 100644 --- a/src/CoreFoundation/Dispatch.cs +++ b/src/CoreFoundation/Dispatch.cs @@ -292,8 +292,13 @@ public void Resume () [DllImport (Constants.libcLibrary)] extern static void dispatch_set_context (IntPtr o, IntPtr ctx); +#if NET + [DllImport (Constants.libcLibrary)] + extern unsafe static void dispatch_apply_f (IntPtr iterations, IntPtr queue, IntPtr ctx, delegate* unmanaged dispatch); +#else [DllImport (Constants.libcLibrary)] extern static void dispatch_apply_f (IntPtr iterations, IntPtr queue, IntPtr ctx, dispatch_callback_iterations_t dispatch); +#endif public IntPtr Context { get { @@ -354,14 +359,21 @@ public static DispatchQueue MainQueue { // // Dispatching // +#if !NET internal delegate void dispatch_callback_t (IntPtr context); internal static readonly dispatch_callback_t static_dispatch = static_dispatcher_to_managed; internal delegate void dispatch_callback_iterations_t (IntPtr context, IntPtr count); internal static readonly dispatch_callback_iterations_t static_dispatch_iterations = static_dispatcher_iterations_to_managed; +#endif +#if NET + [UnmanagedCallersOnly] + internal static void static_dispatcher_to_managed (IntPtr context) +#else [MonoPInvokeCallback (typeof (dispatch_callback_t))] static void static_dispatcher_to_managed (IntPtr context) +#endif { GCHandle gch = GCHandle.FromIntPtr (context); var obj = gch.Target as Tuple; @@ -388,7 +400,11 @@ static void static_dispatcher_to_managed (IntPtr context) } +#if NET + [UnmanagedCallersOnly] +#else [MonoPInvokeCallback (typeof (dispatch_callback_iterations_t))] +#endif static void static_dispatcher_iterations_to_managed (IntPtr context, IntPtr count) { GCHandle gch = GCHandle.FromIntPtr (context); @@ -415,10 +431,13 @@ static void static_dispatcher_iterations_to_managed (IntPtr context, IntPtr coun } } - +#if !NET internal static readonly dispatch_callback_t free_gchandle = static_free_gchandle; [MonoPInvokeCallback (typeof (dispatch_callback_t))] +#else + [UnmanagedCallersOnly] +#endif static void static_free_gchandle (IntPtr context) { GCHandle.FromIntPtr (context).Free (); @@ -428,8 +447,13 @@ public void DispatchAsync (Action action) { if (action is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (action)); - +#if NET + unsafe { + dispatch_async_f (Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), &static_dispatcher_to_managed); + } +#else dispatch_async_f (Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), static_dispatch); +#endif } public void DispatchAsync (DispatchBlock block) @@ -445,7 +469,13 @@ public void DispatchSync (Action action) if (action is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (action)); +#if NET + unsafe { + dispatch_sync_f (Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), &static_dispatcher_to_managed); + } +#else dispatch_sync_f (Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), static_dispatch); +#endif } public void DispatchSync (DispatchBlock block) @@ -461,7 +491,13 @@ public void DispatchBarrierAsync (Action action) if (action is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (action)); +#if NET + unsafe { + dispatch_barrier_async_f (Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), &static_dispatcher_to_managed); + } +#else dispatch_barrier_async_f (Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), static_dispatch); +#endif } public void DispatchBarrierAsync (DispatchBlock block) @@ -477,7 +513,13 @@ public void DispatchBarrierSync (Action action) if (action is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (action)); +#if NET + unsafe { + dispatch_barrier_sync_f (Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), &static_dispatcher_to_managed); + } +#else dispatch_barrier_sync_f (Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), static_dispatch); +#endif } public void DispatchBarrierSync (DispatchBlock block) @@ -492,8 +534,13 @@ public void DispatchAfter (DispatchTime when, Action action) { if (action is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (action)); - +#if NET + unsafe { + dispatch_after_f (when.Nanoseconds, Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), &static_dispatcher_to_managed); + } +#else dispatch_after_f (when.Nanoseconds, Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), static_dispatch); +#endif } public void DispatchAfter (DispatchTime when, DispatchBlock block) @@ -508,12 +555,24 @@ public void Submit (Action action, long times) { if (action is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (action)); +#if NET + unsafe { + dispatch_apply_f ((IntPtr) times, Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), &static_dispatcher_iterations_to_managed); + } +#else dispatch_apply_f ((IntPtr) times, Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, this)), static_dispatch_iterations); +#endif } public void SetSpecific (IntPtr key, object context) { +#if NET + unsafe { + dispatch_queue_set_specific (GetCheckedHandle (), key, (IntPtr) GCHandle.Alloc (context), &static_free_gchandle); + } +#else dispatch_queue_set_specific (GetCheckedHandle (), key, (IntPtr) GCHandle.Alloc (context), free_gchandle); +#endif } public object? GetSpecific (IntPtr key) @@ -587,32 +646,57 @@ static IntPtr dispatch_queue_create_with_target (string label, IntPtr attr, IntP [DllImport (Constants.libcLibrary, EntryPoint = "dispatch_queue_create_with_target$V2")] extern static IntPtr dispatch_queue_create_with_target (IntPtr label, IntPtr attr, IntPtr target); +#if NET + [DllImport (Constants.libcLibrary)] + extern unsafe static void dispatch_async_f (IntPtr queue, IntPtr context, delegate* unmanaged dispatch); +#else [DllImport (Constants.libcLibrary)] extern static void dispatch_async_f (IntPtr queue, IntPtr context, dispatch_callback_t dispatch); +#endif [DllImport (Constants.libcLibrary)] extern static void dispatch_async (IntPtr queue, IntPtr block); +#if NET + [DllImport (Constants.libcLibrary)] + extern unsafe static void dispatch_sync_f (IntPtr queue, IntPtr context, delegate* unmanaged dispatch); +#else [DllImport (Constants.libcLibrary)] extern static void dispatch_sync_f (IntPtr queue, IntPtr context, dispatch_callback_t dispatch); +#endif [DllImport (Constants.libcLibrary)] extern static void dispatch_sync (IntPtr queue, IntPtr block); +#if NET + [DllImport (Constants.libcLibrary)] + extern unsafe static void dispatch_barrier_async_f (IntPtr queue, IntPtr context, delegate* unmanaged dispatch); +#else [DllImport (Constants.libcLibrary)] extern static void dispatch_barrier_async_f (IntPtr queue, IntPtr context, dispatch_callback_t dispatch); +#endif [DllImport (Constants.libcLibrary)] extern static void dispatch_barrier_async (IntPtr queue, IntPtr block); +#if NET + [DllImport (Constants.libcLibrary)] + extern unsafe static void dispatch_barrier_sync_f (IntPtr queue, IntPtr context, delegate* unmanaged dispatch); +#else [DllImport (Constants.libcLibrary)] extern static void dispatch_barrier_sync_f (IntPtr queue, IntPtr context, dispatch_callback_t dispatch); +#endif [DllImport (Constants.libcLibrary)] extern static void dispatch_barrier_sync (IntPtr queue, IntPtr block); +#if NET + [DllImport (Constants.libcLibrary)] + extern unsafe static void dispatch_after_f (/* dispath_time_t */ ulong time, IntPtr queue, IntPtr context, delegate* unmanaged dispatch); +#else [DllImport (Constants.libcLibrary)] extern static void dispatch_after_f (/* dispath_time_t */ ulong time, IntPtr queue, IntPtr context, dispatch_callback_t dispatch); +#endif [DllImport (Constants.libcLibrary)] extern static void dispatch_after (/* dispath_time_t */ ulong time, IntPtr queue, IntPtr block); @@ -639,8 +723,13 @@ static IntPtr dispatch_queue_create_with_target (string label, IntPtr attr, IntP // this returns a "const char*" so we cannot make a string out of it since it will be freed (and crash) extern static IntPtr dispatch_queue_get_label (IntPtr queue); +#if NET + [DllImport (Constants.libcLibrary)] + extern unsafe static void dispatch_queue_set_specific (IntPtr queue, /* const void* */ IntPtr key, /* void *_Nullable */ IntPtr context, delegate* unmanaged /* _Nullable */ destructor); +#else [DllImport (Constants.libcLibrary)] extern static void dispatch_queue_set_specific (IntPtr queue, /* const void* */ IntPtr key, /* void *_Nullable */ IntPtr context, dispatch_callback_t /* _Nullable */ destructor); +#endif [DllImport (Constants.libcLibrary)] extern static IntPtr dispatch_queue_get_specific (IntPtr queue, /* const void* */ IntPtr key); @@ -915,7 +1004,13 @@ public void DispatchAsync (DispatchQueue queue, Action action) if (action is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (action)); +#if NET + unsafe { + dispatch_group_async_f (GetCheckedHandle (), queue.Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, queue)), &DispatchQueue.static_dispatcher_to_managed); + } +#else dispatch_group_async_f (GetCheckedHandle (), queue.Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, queue)), DispatchQueue.static_dispatch); +#endif } public void Notify (DispatchQueue queue, DispatchBlock block) @@ -933,8 +1028,13 @@ public void Notify (DispatchQueue queue, Action action) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (queue)); if (action is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (action)); - +#if NET + unsafe { + dispatch_group_notify_f (GetCheckedHandle (), queue.Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, queue)), &DispatchQueue.static_dispatcher_to_managed); + } +#else dispatch_group_notify_f (GetCheckedHandle (), queue.Handle, (IntPtr) GCHandle.Alloc (Tuple.Create (action, queue)), DispatchQueue.static_dispatch); +#endif } public void Enter () @@ -960,11 +1060,21 @@ public bool Wait (TimeSpan timeout) [DllImport (Constants.libcLibrary)] extern static IntPtr dispatch_group_create (); +#if NET + [DllImport (Constants.libcLibrary)] + extern unsafe static void dispatch_group_async_f (IntPtr group, IntPtr queue, IntPtr context, delegate* unmanaged block); +#else [DllImport (Constants.libcLibrary)] extern static void dispatch_group_async_f (IntPtr group, IntPtr queue, IntPtr context, DispatchQueue.dispatch_callback_t block); +#endif +#if NET + [DllImport (Constants.libcLibrary)] + extern unsafe static void dispatch_group_notify_f (IntPtr group, IntPtr queue, IntPtr context, delegate* unmanaged block); +#else [DllImport (Constants.libcLibrary)] extern static void dispatch_group_notify_f (IntPtr group, IntPtr queue, IntPtr context, DispatchQueue.dispatch_callback_t block); +#endif [DllImport (Constants.libcLibrary)] extern static void dispatch_group_notify (IntPtr group, IntPtr queue, IntPtr block); diff --git a/src/CoreFoundation/OSLog.cs b/src/CoreFoundation/OSLog.cs index 24d6052f7a9..152f9115de5 100644 --- a/src/CoreFoundation/OSLog.cs +++ b/src/CoreFoundation/OSLog.cs @@ -74,8 +74,13 @@ protected internal override void Release () os_release (Handle); } +#if NET + [DllImport (Constants.libSystemLibrary)] + extern static IntPtr os_log_create (IntPtr subsystem, IntPtr category); +#else [DllImport (Constants.libSystemLibrary)] extern static IntPtr os_log_create (string subsystem, string category); +#endif [DllImport (Constants.libSystemLibrary)] extern static IntPtr os_retain (IntPtr handle); @@ -98,8 +103,13 @@ public OSLog (string subsystem, string category) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (subsystem)); if (category is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (category)); - +#if NET + using var subsystemPtr = new TransientString (subsystem); + using var categoryPtr = new TransientString (category); + Handle = os_log_create (subsystemPtr, categoryPtr); +#else Handle = os_log_create (subsystem, category); +#endif } public void Log (string message) diff --git a/tests/cecil-tests/BlittablePInvokes.cs b/tests/cecil-tests/BlittablePInvokes.cs index 3c9fba405e0..2cefdb10bfd 100644 --- a/tests/cecil-tests/BlittablePInvokes.cs +++ b/tests/cecil-tests/BlittablePInvokes.cs @@ -41,7 +41,7 @@ public BlitAndReason (bool isBlittable, string reason) public string Reason; } - [Ignore ("work in progress - there are 25 failures, mostly due to delegates")] + [Ignore ("work in progress - there are 6 failures, mostly due to delegates")] [TestCaseSource (typeof (Helper), nameof (Helper.NetPlatformImplementationAssemblyDefinitions))] public void CheckForNonBlittablePInvokes (AssemblyInfo info) {