// ----------------------------------------------------------------------------- // file="L4.PredictorQueue" // Project: StgSharp // Copyright (c) Nitload. // SPDX-License-Identifier: MIT // ----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Nitload.Common.HighPerformance.Memory { public partial class L4 { private volatile int _consume; private volatile int _enter; private volatile int _predict; private int _queue_sync; internal void DropPredictor( IL4Predictor predictor ) { if (predictor is null) { return; } SpinWait sp = new(); while (Interlocked.CompareExchange(ref _queue_sync, 1, 0) != 0) { sp.SpinOnce(); } try { unchecked { for (int i = _consume; i < _predict; i++) { byte idx = (byte)i; if (ReferenceEquals(predictor, _ring[idx])) { int end = _predict; for (int move = i; move < end - 1; move++) { _ring[(byte)move] = _ring[(byte)(move + 1)]; } _ring[(byte)(end - 1)] = default!; _predict = end - 1; return; } } } } finally { _ = Interlocked.Exchange(ref _queue_sync, 0); } } internal bool MoveNextPredictor() { int cur = Interlocked.Increment(ref _predict); return cur < _enter; } internal void RegistPredictor( IL4Predictor predictor ) { if (predictor is null) { return; } SpinWait sp = new(); wait_for_spare: WaitForSpare(); while (Interlocked.CompareExchange(ref _queue_sync, 1, 0) != 0) { sp.SpinOnce(); } if (_enter - _consume >= PredictorRingCapacity) { _ = Interlocked.Exchange(ref _queue_sync, 0); goto wait_for_spare; } try { unchecked { byte idx = (byte)_enter; _enter++; _ring[idx] = predictor; } } finally { _ = Interlocked.Exchange(ref _queue_sync, 0); } } internal bool TryGetCurrentPredictor( out IL4Predictor predictor ) { int cur = _predict; if (cur >= _enter) { predictor = default!; return false; } unchecked { predictor = _ring[(byte)cur]; return true; } } private void WaitForSpare() { int spin_count = 0; while (_enter - _consume >= PredictorRingCapacity) { switch (spin_count) { case < 1024: spin_count++; break; case < 65536: spin_count++; Thread.SpinWait(1); break; default: Thread.Sleep(1); break; } } } } }