XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using XFESystem.Desktop;

namespace XFESystem.Platform;

/// <summary>One real managed thread owns its bounded FIFO. Runtime startup must verify threads, GC and EH before constructing it.</summary>
public sealed class DesktopBackgroundWorkScheduler : IEditorBackgroundWorkScheduler, IDisposable
{
    private const int Capacity = 64;
    private readonly object gate = new();
    private readonly Queue<Action> pending = new(Capacity);
    private readonly Thread worker;
    private readonly Action<Exception>? reportError;
    private bool stopping;
    private int workerThreadId;
    public int WorkerThreadId => Volatile.Read(ref workerThreadId);

    public DesktopBackgroundWorkScheduler(Action<Exception>? reportError = null)
    {
        this.reportError = reportError;
        using var ready = new ManualResetEventSlim();
        worker = new Thread(() => Run(ready)) { IsBackground = true };
        worker.Start();
        if (!ready.Wait(10_000)) throw new InvalidOperationException("The managed browser worker did not start.");
        if (WorkerThreadId == Environment.CurrentManagedThreadId) throw new InvalidOperationException("The browser worker shares the UI thread.");
    }

    public bool TryQueue(Action work)
    {
        ArgumentNullException.ThrowIfNull(work);
        lock (gate)
        {
            if (stopping || pending.Count == Capacity) return false;
            pending.Enqueue(work); Monitor.Pulse(gate); return true;
        }
    }

    private void Run(ManualResetEventSlim ready)
    {
        Volatile.Write(ref workerThreadId, Environment.CurrentManagedThreadId); ready.Set();
        for (;;)
        {
            Action work;
            lock (gate)
            {
                while (pending.Count == 0 && !stopping) Monitor.Wait(gate);
                if (pending.Count == 0) return;
                work = pending.Dequeue();
            }
            try { work(); }
            catch (Exception error) when (error is not OutOfMemoryException and not StackOverflowException)
            { reportError?.Invoke(error); }
        }
    }

    public void Dispose()
    {
        lock (gate) { stopping = true; Monitor.PulseAll(gate); }
        if (Environment.CurrentManagedThreadId != WorkerThreadId && !worker.Join(10_000))
            throw new InvalidOperationException("The managed browser worker did not finish.");
    }
}