// Copyright (C) 2026 SharpEmu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later using System.Collections.Concurrent; namespace SharpEmu.HLE; /// /// Runs work on the real process main thread. macOS only allows AppKit (and /// therefore GLFW windowing) on that thread, so the CLI moves emulation onto /// a worker thread, parks the main thread in , and the /// video presenter posts its window loop here. On other platforms /// stays false and nothing changes. /// public static class HostMainThread { private static readonly BlockingCollection _work = new(); private static Action? _shutdownRequestHandler; public static bool IsAvailable { get; private set; } /// /// Registers a callback invoked by so a /// long-running posted work item (the presenter's window loop) can be /// asked to return to the pump. /// public static void SetShutdownRequestHandler(Action handler) => _shutdownRequestHandler = handler; /// Marks the pump as present. Call before guest code can run. public static void Enable() => IsAvailable = true; public static void Post(Action work) { try { _work.Add(work); } catch (InvalidOperationException) { // Shutdown already requested; the process is exiting. } } /// /// Services posted work on the calling (main) thread until /// is called and the queue drains. /// public static void Pump() { foreach (var work in _work.GetConsumingEnumerable()) { try { work(); } catch (Exception exception) { Console.Error.WriteLine($"[LOADER][ERROR] Main-thread work failed: {exception}"); } } } public static void Shutdown() { IsAvailable = false; try { _shutdownRequestHandler?.Invoke(); } catch (Exception exception) { Console.Error.WriteLine($"[LOADER][WARN] Main-thread shutdown handler failed: {exception.Message}"); } _work.CompleteAdding(); } }