diff --git a/WorkerQueues.cs b/WorkerQueues.cs
new file mode 100644
index 0000000..c40e6b8
--- /dev/null
+++ b/WorkerQueues.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace BinaryNinja
+{
+ internal static partial class NativeDelegates
+ {
+ [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
+ internal delegate void BNWorkerAction(IntPtr context);
+ }
+
+ public static partial class Core
+ {
+ private enum WorkerQueueKind
+ {
+ Default,
+ Priority,
+ Interactive
+ }
+
+ private static readonly NativeDelegates.BNWorkerAction workerActionCallback =
+ new NativeDelegates.BNWorkerAction(Core.InvokeWorkerAction);
+
+ /// Enqueues a named action on the default analysis worker queue.
+ public static void WorkerEnqueue(Action action, string name = "")
+ {
+ Core.EnqueueWorker(WorkerQueueKind.Default, action, name);
+ }
+
+ /// Enqueues a named action ahead of normal analysis worker work.
+ public static void WorkerPriorityEnqueue(Action action, string name = "")
+ {
+ Core.EnqueueWorker(WorkerQueueKind.Priority, action, name);
+ }
+
+ /// Enqueues a named action on the interactive worker queue.
+ public static void WorkerInteractiveEnqueue(Action action, string name = "")
+ {
+ Core.EnqueueWorker(WorkerQueueKind.Interactive, action, name);
+ }
+
+ private static void EnqueueWorker(WorkerQueueKind kind, Action action, string name)
+ {
+ if (null == action)
+ {
+ throw new ArgumentNullException(nameof(action));
+ }
+
+ GCHandle context = GCHandle.Alloc(action);
+ IntPtr contextPointer = GCHandle.ToIntPtr(context);
+ IntPtr callback = Marshal.GetFunctionPointerForDelegate(
+ Core.workerActionCallback
+ );
+
+ try
+ {
+ switch (kind)
+ {
+ case WorkerQueueKind.Default:
+ NativeMethods.BNWorkerEnqueueNamed(
+ contextPointer,
+ callback,
+ name ?? string.Empty
+ );
+ break;
+ case WorkerQueueKind.Priority:
+ NativeMethods.BNWorkerPriorityEnqueueNamed(
+ contextPointer,
+ callback,
+ name ?? string.Empty
+ );
+ break;
+ case WorkerQueueKind.Interactive:
+ NativeMethods.BNWorkerInteractiveEnqueueNamed(
+ contextPointer,
+ callback,
+ name ?? string.Empty
+ );
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(kind));
+ }
+ }
+ catch
+ {
+ if (context.IsAllocated)
+ {
+ context.Free();
+ }
+
+ throw;
+ }
+ }
+
+ private static void InvokeWorkerAction(IntPtr contextPointer)
+ {
+ GCHandle context = GCHandle.FromIntPtr(contextPointer);
+ try
+ {
+ Action? action = context.Target as Action;
+ if (null != action)
+ {
+ action();
+ }
+ }
+ catch (Exception exception)
+ {
+ Core.LogError("Unhandled exception in worker action: {0}", exception);
+ }
+ finally
+ {
+ if (context.IsAllocated)
+ {
+ context.Free();
+ }
+ }
+ }
+ }
+}