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

XFESystem

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

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;

namespace XFESystem.Kernel;

/// <summary>Actual single-CPU IRQ preemption, independent EH chains and live roots during collection.</summary>
internal static class NativeThreadRegression
{
    [DllImport("libSystem.Native", EntryPoint = "XfeRuntimeThreadEhContractVersion")]
    [SuppressGCTransition]
    private static extern int ThreadEhContractVersion();
    [DllImport("libSystem.Native", EntryPoint = "XfeRuntimeCurrentSchedulerThreadId")]
    [SuppressGCTransition]
    internal static extern int CurrentThreadId();
    private sealed class Probe
    {
        public int ThreadId, ManagedThreadId, InCatch, Steps, BusyStarted, BusyObserved, BusyProgress, Failure, Complete;
        public Thread ManagedThread = null!;
        public Probe Peer = null!;
    }
    private static Probe first = null!, second = null!;
    private static int collections, preemptionChecks, threadStaticChecks, cancel;
    [ThreadStatic] private static int threadStaticToken;
    [ThreadStatic] private static byte[]? threadStaticPayload;
    private static long checksum;
    public static bool Passed { get; private set; }
    public static int Steps => Volatile.Read(ref first.Steps) + Volatile.Read(ref second.Steps);
    public static int Collections => Volatile.Read(ref collections);
    public static int FirstThreadId => Volatile.Read(ref first.ThreadId);
    public static int SecondThreadId => Volatile.Read(ref second.ThreadId);
    public static int PreemptionChecks => Volatile.Read(ref preemptionChecks);
    public static int ThreadStaticChecks => Volatile.Read(ref threadStaticChecks);
    public static int FirstManagedThreadId => Volatile.Read(ref first.ManagedThreadId);
    public static int SecondManagedThreadId => Volatile.Read(ref second.ManagedThreadId);
    public static int FirstFailure => Volatile.Read(ref first.Failure);
    public static int SecondFailure => Volatile.Read(ref second.Failure);
    public static bool Run()
    {
        Passed = false;
        first = new(); second = new(); first.Peer = second; second.Peer = first;
        collections = preemptionChecks = threadStaticChecks = cancel = 0;
        if (ThreadEhContractVersion() != 1) return false;
        var firstThread = new Thread(() => Exercise(first), NativeManagedWorkScheduler.StackBytes);
        var secondThread = new Thread(() => Exercise(second), NativeManagedWorkScheduler.StackBytes);
        firstThread.Start(); secondThread.Start();
        long deadline = Stopwatch.GetTimestamp() + Stopwatch.Frequency * 20;
        while ((Volatile.Read(ref first.Complete) == 0 || Volatile.Read(ref second.Complete) == 0) && Stopwatch.GetTimestamp() < deadline) Thread.Sleep(1);
        if (Volatile.Read(ref first.Complete) == 0 || Volatile.Read(ref second.Complete) == 0) Volatile.Write(ref cancel, 1);
        Passed = Volatile.Read(ref first.Complete) != 0 && Volatile.Read(ref second.Complete) != 0 &&
            FirstFailure == 0 && SecondFailure == 0 && FirstThreadId != 0 && SecondThreadId != 0 && FirstThreadId != SecondThreadId &&
            FirstManagedThreadId != 0 && SecondManagedThreadId != 0 && FirstManagedThreadId != SecondManagedThreadId && !ReferenceEquals(first.ManagedThread, second.ManagedThread) &&
            Steps == 32 && Collections == 4 && PreemptionChecks == 32 && ThreadStaticChecks == 32;
        return Passed;
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    private static void Exercise(Probe state)
    {
        try
        {
            Volatile.Write(ref state.ThreadId, CurrentThreadId());
            state.ManagedThread = Thread.CurrentThread;
            Volatile.Write(ref state.ManagedThreadId, state.ManagedThread.ManagedThreadId);
            if (state.ManagedThread.IsThreadPoolThread) { Volatile.Write(ref state.Failure, 6); Volatile.Write(ref state.Complete, 1); return; }
            threadStaticToken = state.ThreadId;
            threadStaticPayload = new byte[17]; threadStaticPayload[0] = (byte)state.ThreadId; threadStaticPayload[^1] = 211;
            var token = new InvalidOperationException("XFE independent thread exception");
            var payload = new byte[8192]; payload[0] = 91; payload[^1] = 113;
            for (int round = 0; round < 16 && Volatile.Read(ref cancel) == 0; round++)
            {
                try { ThrowToken(token); }
                catch (InvalidOperationException caught)
                {
                    if (!ReferenceEquals(token, caught)) { Volatile.Write(ref state.Failure, 1); break; }
                    Volatile.Write(ref state.InCatch, round + 1);
                    while (Volatile.Read(ref state.Peer.InCatch) < round + 1 && Volatile.Read(ref cancel) == 0 && Volatile.Read(ref state.Peer.Complete) == 0) Thread.Sleep(1);
                    if (Volatile.Read(ref cancel) != 0 || Volatile.Read(ref state.Peer.Complete) != 0) break;
                    int before = Volatile.Read(ref state.Peer.BusyProgress), progress = Volatile.Read(ref state.BusyProgress);
                    int phase = round + 1;
                    long started = Stopwatch.GetTimestamp(), minimum = started + Stopwatch.Frequency / 20;
                    long deadline = started + Stopwatch.Frequency * 2;
                    bool observedPeer = false;
                    // Take the peer snapshot BEFORE publishing readiness. The
                    // peer cannot leave this round until we have observed a
                    // counter change after this point and published that fact.
                    Volatile.Write(ref state.BusyStarted, phase);
                    long value = round;
                    // Fifty milliseconds exceeds the scheduler quantum. No sleep,
                    // yield, wait, allocation, lock or logging occurs in this span.
                    while (true)
                    {
                        value = unchecked(value * 6364136223846793005L + 1);
                        Volatile.Write(ref state.BusyProgress, ++progress);
                        if (!observedPeer && Volatile.Read(ref state.Peer.BusyStarted) >= phase && Volatile.Read(ref state.Peer.BusyProgress) != before)
                        {
                            observedPeer = true;
                            Volatile.Write(ref state.BusyObserved, phase);
                        }
                        long now = Stopwatch.GetTimestamp();
                        if (now >= deadline) { Volatile.Write(ref state.Failure, 2); break; }
                        if (Volatile.Read(ref cancel) != 0) { Volatile.Write(ref state.Failure, 10); break; }
                        if (Volatile.Read(ref state.Peer.Failure) != 0) { Volatile.Write(ref state.Failure, 11); break; }
                        // Complete publishes every earlier peer store. Acquire
                        // Observed AFTER Complete: a cached earlier false can
                        // become stale while an IRQ lets the peer finish.
                        if (Volatile.Read(ref state.Peer.Complete) != 0 &&
                            (!observedPeer || Volatile.Read(ref state.Peer.BusyObserved) < phase))
                        { Volatile.Write(ref state.Failure, 12); break; }
                        if (observedPeer && Volatile.Read(ref state.Peer.BusyObserved) >= phase && now >= minimum) break;
                    }
                    Interlocked.Exchange(ref checksum, value);
                    if (Volatile.Read(ref state.Failure) != 0) break;
                    Interlocked.Increment(ref preemptionChecks);
                    Thread.Sleep(1);
                    if (round == 4 || round == 12) { GC.Collect(); Interlocked.Increment(ref collections); }
                    try { throw; }
                    catch (InvalidOperationException rethrown)
                    { if (!ReferenceEquals(token, rethrown)) { Volatile.Write(ref state.Failure, 3); break; } }
                    if (payload[0] != 91 || payload[^1] != 113) { Volatile.Write(ref state.Failure, 4); break; }
                    if (threadStaticToken != state.ThreadId || threadStaticPayload is null || threadStaticPayload[0] != (byte)state.ThreadId || threadStaticPayload[^1] != 211)
                    { Volatile.Write(ref state.Failure, 7); break; }
                    if (!ReferenceEquals(Thread.CurrentThread, state.ManagedThread) || Thread.CurrentThread.IsThreadPoolThread || Thread.CurrentThread.ManagedThreadId != state.ManagedThreadId)
                    { Volatile.Write(ref state.Failure, 8); break; }
                    if (ReferenceEquals(state.ManagedThread, state.Peer.ManagedThread) || state.ManagedThreadId == Volatile.Read(ref state.Peer.ManagedThreadId))
                    { Volatile.Write(ref state.Failure, 9); break; }
                    Interlocked.Increment(ref threadStaticChecks);
                    Volatile.Write(ref state.Steps, round + 1);
                    GC.KeepAlive(payload); GC.KeepAlive(token);
                }
            }
        }
        catch (Exception) { Volatile.Write(ref state.Failure, 5); }
        Volatile.Write(ref state.Complete, 1);
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    private static void ThrowToken(InvalidOperationException token) => throw token;
}