CPF/CPF.Mac/Mac/CoreFoundation/DispatchQueue.cs
2023-11-21 23:05:03 +08:00

209 lines
4.9 KiB
C#

using CPF.Mac.Foundation;
using CPF.Mac.ObjCRuntime;
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace CPF.Mac.CoreFoundation
{
public class DispatchQueue : DispatchObject
{
internal delegate void dispatch_callback_t(IntPtr context);
private static IntPtr main_q;
private static object lockobj = new object();
internal static readonly dispatch_callback_t static_dispatch = static_dispatcher_to_managed;
public string Label
{
get
{
if (handle == IntPtr.Zero)
{
throw new ObjectDisposedException("DispatchQueue");
}
return Marshal.PtrToStringAnsi(dispatch_queue_get_label(handle));
}
}
public IntPtr Context
{
get
{
Check();
return dispatch_get_context(handle);
}
set
{
Check();
dispatch_set_context(handle, value);
}
}
[Obsolete("Deprecated in iOS 6.0")]
public static DispatchQueue CurrentQueue => new DispatchQueue(dispatch_get_current_queue(), owns: false);
public static DispatchQueue DefaultGlobalQueue => new DispatchQueue(dispatch_get_global_queue((IntPtr)0, IntPtr.Zero), owns: false);
public static DispatchQueue MainQueue
{
get
{
lock (lockobj)
{
if (main_q == IntPtr.Zero)
{
main_q = Dlfcn.dlsym((IntPtr)(-2), "_dispatch_main_q");
if (main_q == IntPtr.Zero)
{
IntPtr handle = Dlfcn.dlopen("/usr/lib/libSystem.dylib", 0);
main_q = Dlfcn.GetIndirect(handle, "_dispatch_main_q");
Dlfcn.dlclose(handle);
}
}
}
if (main_q == IntPtr.Zero)
{
return PInvokeDispatchGetMainQueue();
}
return new DispatchQueue(main_q, owns: false);
}
}
[Preserve(Conditional = true)]
internal DispatchQueue(IntPtr handle, bool owns)
: base(handle, owns)
{
}
public DispatchQueue(IntPtr handle)
: base(handle, owns: false)
{
}
public DispatchQueue(string label)
{
handle = dispatch_queue_create(label, IntPtr.Zero);
if (handle == IntPtr.Zero)
{
throw new Exception("Error creating dispatch queue");
}
}
[DllImport("libc")]
private static extern void dispatch_suspend(IntPtr o);
public void Suspend()
{
Check();
dispatch_suspend(handle);
}
[DllImport("libc")]
private static extern void dispatch_resume(IntPtr o);
public void Resume()
{
Check();
dispatch_resume(handle);
}
[DllImport("libc")]
private static extern IntPtr dispatch_get_context(IntPtr o);
[DllImport("libc")]
private static extern void dispatch_set_context(IntPtr o, IntPtr ctx);
public static DispatchQueue GetGlobalQueue(DispatchQueuePriority priority)
{
return new DispatchQueue(dispatch_get_global_queue((IntPtr)(int)priority, IntPtr.Zero), owns: false);
}
private static DispatchQueue PInvokeDispatchGetMainQueue()
{
return new DispatchQueue(dispatch_get_main_queue(), owns: false);
}
[MonoPInvokeCallback(typeof(dispatch_callback_t))]
private static void static_dispatcher_to_managed(IntPtr context)
{
GCHandle gCHandle = GCHandle.FromIntPtr(context);
Tuple<NSAction, DispatchQueue> tuple = gCHandle.Target as Tuple<NSAction, DispatchQueue>;
if (tuple != null)
{
SynchronizationContext current = SynchronizationContext.Current;
if (current == null)
{
SynchronizationContext.SetSynchronizationContext(new DispatchQueueSynchronizationContext(tuple.Item2));
}
try
{
tuple.Item1();
}
catch
{
gCHandle.Free();
throw;
}
finally
{
if (current == null)
{
SynchronizationContext.SetSynchronizationContext(null);
}
}
}
gCHandle.Free();
}
public void DispatchAsync(NSAction action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
dispatch_async_f(handle, (IntPtr)GCHandle.Alloc(Tuple.Create(action, this)), static_dispatch);
}
public void DispatchSync(NSAction action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
dispatch_sync_f(handle, (IntPtr)GCHandle.Alloc(Tuple.Create(action, this)), static_dispatch);
}
[DllImport("libc")]
private static extern IntPtr dispatch_queue_create(string label, IntPtr attr);
[DllImport("libc")]
private static extern void dispatch_async_f(IntPtr queue, IntPtr context, dispatch_callback_t dispatch);
[DllImport("libc")]
private static extern void dispatch_sync_f(IntPtr queue, IntPtr context, dispatch_callback_t dispatch);
[DllImport("libc")]
private static extern IntPtr dispatch_get_current_queue();
[DllImport("libc")]
private static extern IntPtr dispatch_get_global_queue(IntPtr priority, IntPtr flags);
[DllImport("libc")]
private static extern IntPtr dispatch_get_main_queue();
[DllImport("libc")]
private static extern IntPtr dispatch_queue_get_label(IntPtr queue);
[DllImport("libc")]
private static extern IntPtr dispatch_main();
public static void MainIteration()
{
dispatch_main();
}
}
}