From b8133c19971c7a2026af803003fafedbdb70488e Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 18 Sep 2018 20:36:43 -0300 Subject: Thread scheduler rewrite (#393) * Started to rewrite the thread scheduler * Add a single core-like scheduling mode, enabled by default * Clear exclusive monitor on context switch * Add SetThreadActivity, misc fixes * Implement WaitForAddress and SignalToAddress svcs, misc fixes * Misc fixes (on SetActivity and Arbiter), other tweaks * Rebased * Add missing null check * Rename multicore key on config, fix UpdatePriorityInheritance * Make scheduling data MLQs private * nit: Ordering --- Ryujinx.HLE/HOS/Kernel/KTimeManager.cs | 134 +++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 Ryujinx.HLE/HOS/Kernel/KTimeManager.cs (limited to 'Ryujinx.HLE/HOS/Kernel/KTimeManager.cs') diff --git a/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs b/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs new file mode 100644 index 00000000..47a3c86c --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class KTimeManager : IDisposable + { + private class WaitingObject + { + public IKFutureSchedulerObject Object { get; private set; } + + public long TimePoint { get; private set; } + + public WaitingObject(IKFutureSchedulerObject Object, long TimePoint) + { + this.Object = Object; + this.TimePoint = TimePoint; + } + } + + private List WaitingObjects; + + private AutoResetEvent WaitEvent; + + private Stopwatch Counter; + + private bool KeepRunning; + + public KTimeManager() + { + WaitingObjects = new List(); + + Counter = new Stopwatch(); + + Counter.Start(); + + KeepRunning = true; + + Thread Work = new Thread(WaitAndCheckScheduledObjects); + + Work.Start(); + } + + public void ScheduleFutureInvocation(IKFutureSchedulerObject Object, long Timeout) + { + lock (WaitingObjects) + { + long TimePoint = Counter.ElapsedMilliseconds + ConvertNanosecondsToMilliseconds(Timeout); + + WaitingObjects.Add(new WaitingObject(Object, TimePoint)); + } + + WaitEvent.Set(); + } + + private long ConvertNanosecondsToMilliseconds(long Timeout) + { + Timeout /= 1000000; + + if ((ulong)Timeout > int.MaxValue) + { + return int.MaxValue; + } + + return Timeout; + } + + public void UnscheduleFutureInvocation(IKFutureSchedulerObject Object) + { + lock (WaitingObjects) + { + WaitingObjects.RemoveAll(x => x.Object == Object); + } + } + + private void WaitAndCheckScheduledObjects() + { + using (WaitEvent = new AutoResetEvent(false)) + { + while (KeepRunning) + { + Monitor.Enter(WaitingObjects); + + WaitingObject Next = WaitingObjects.OrderBy(x => x.TimePoint).FirstOrDefault(); + + Monitor.Exit(WaitingObjects); + + if (Next != null) + { + long TimePoint = Counter.ElapsedMilliseconds; + + if (Next.TimePoint > TimePoint) + { + WaitEvent.WaitOne((int)(Next.TimePoint - TimePoint)); + } + + Monitor.Enter(WaitingObjects); + + bool TimeUp = Counter.ElapsedMilliseconds >= Next.TimePoint && WaitingObjects.Remove(Next); + + Monitor.Exit(WaitingObjects); + + if (TimeUp) + { + Next.Object.TimeUp(); + } + } + else + { + WaitEvent.WaitOne(); + } + } + } + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + KeepRunning = false; + + WaitEvent?.Set(); + } + } + } +} \ No newline at end of file -- cgit v1.2.3