From f07e1fa8afec8e228abb8db16a99263d53e03279 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 18 Sep 2018 20:36:43 -0300 Subject: [PATCH] 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 --- AThread.cs | 28 ++++++++++++++++------------ Instruction/AInstEmitMemoryEx.cs | 3 +++ Memory/AMemory.cs | 28 ++++++++++++++-------------- State/AThreadState.cs | 21 +++++++++++++++++++++ 4 files changed, 54 insertions(+), 26 deletions(-) diff --git a/AThread.cs b/AThread.cs index 7b8360f..76b36da 100644 --- a/AThread.cs +++ b/AThread.cs @@ -10,11 +10,9 @@ namespace ChocolArm64 public AThreadState ThreadState { get; private set; } public AMemory Memory { get; private set; } - private long EntryPoint; - private ATranslator Translator; - private Thread Work; + public Thread Work; public event EventHandler WorkFinished; @@ -24,13 +22,21 @@ namespace ChocolArm64 { this.Translator = Translator; this.Memory = Memory; - this.EntryPoint = EntryPoint; ThreadState = new AThreadState(); ThreadState.ExecutionMode = AExecutionMode.AArch64; ThreadState.Running = true; + + Work = new Thread(delegate() + { + Translator.ExecuteSubroutine(this, EntryPoint); + + Memory.RemoveMonitor(ThreadState.Core); + + WorkFinished?.Invoke(this, EventArgs.Empty); + }); } public bool Execute() @@ -40,14 +46,7 @@ namespace ChocolArm64 return false; } - Work = new Thread(delegate() - { - Translator.ExecuteSubroutine(this, EntryPoint); - - Memory.RemoveMonitor(ThreadState); - - WorkFinished?.Invoke(this, EventArgs.Empty); - }); + Work.Name = "cpu_thread_" + Work.ManagedThreadId; Work.Start(); @@ -59,6 +58,11 @@ namespace ChocolArm64 ThreadState.Running = false; } + public void RequestInterrupt() + { + ThreadState.RequestInterrupt(); + } + public bool IsCurrentThread() { return Thread.CurrentThread == Work; diff --git a/Instruction/AInstEmitMemoryEx.cs b/Instruction/AInstEmitMemoryEx.cs index e59cadd..cf19b4a 100644 --- a/Instruction/AInstEmitMemoryEx.cs +++ b/Instruction/AInstEmitMemoryEx.cs @@ -1,5 +1,6 @@ using ChocolArm64.Decoder; using ChocolArm64.Memory; +using ChocolArm64.State; using ChocolArm64.Translation; using System; using System.Reflection.Emit; @@ -170,6 +171,8 @@ namespace ChocolArm64.Instruction Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdarg(ATranslatedSub.StateArgIdx); + Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Core)); + if (Rn != -1) { Context.EmitLdint(Rn); diff --git a/Memory/AMemory.cs b/Memory/AMemory.cs index 806a0b8..2cb9b16 100644 --- a/Memory/AMemory.cs +++ b/Memory/AMemory.cs @@ -41,7 +41,7 @@ namespace ChocolArm64.Memory } } - private Dictionary Monitors; + private Dictionary Monitors; private ConcurrentDictionary ObservedPages; @@ -53,7 +53,7 @@ namespace ChocolArm64.Memory public AMemory(IntPtr Ram) { - Monitors = new Dictionary(); + Monitors = new Dictionary(); ObservedPages = new ConcurrentDictionary(); @@ -69,17 +69,17 @@ namespace ChocolArm64.Memory } } - public void RemoveMonitor(AThreadState State) + public void RemoveMonitor(int Core) { lock (Monitors) { - ClearExclusive(State); + ClearExclusive(Core); - Monitors.Remove(State); + Monitors.Remove(Core); } } - public void SetExclusive(AThreadState ThreadState, long Position) + public void SetExclusive(int Core, long Position) { Position &= ~ErgMask; @@ -93,11 +93,11 @@ namespace ChocolArm64.Memory } } - if (!Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon)) + if (!Monitors.TryGetValue(Core, out ArmMonitor ThreadMon)) { ThreadMon = new ArmMonitor(); - Monitors.Add(ThreadState, ThreadMon); + Monitors.Add(Core, ThreadMon); } ThreadMon.Position = Position; @@ -105,7 +105,7 @@ namespace ChocolArm64.Memory } } - public bool TestExclusive(AThreadState ThreadState, long Position) + public bool TestExclusive(int Core, long Position) { //Note: Any call to this method also should be followed by a //call to ClearExclusiveForStore if this method returns true. @@ -113,7 +113,7 @@ namespace ChocolArm64.Memory Monitor.Enter(Monitors); - if (!Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon)) + if (!Monitors.TryGetValue(Core, out ArmMonitor ThreadMon)) { return false; } @@ -128,9 +128,9 @@ namespace ChocolArm64.Memory return ExState; } - public void ClearExclusiveForStore(AThreadState ThreadState) + public void ClearExclusiveForStore(int Core) { - if (Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon)) + if (Monitors.TryGetValue(Core, out ArmMonitor ThreadMon)) { ThreadMon.ExState = false; } @@ -138,11 +138,11 @@ namespace ChocolArm64.Memory Monitor.Exit(Monitors); } - public void ClearExclusive(AThreadState ThreadState) + public void ClearExclusive(int Core) { lock (Monitors) { - if (Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon)) + if (Monitors.TryGetValue(Core, out ArmMonitor ThreadMon)) { ThreadMon.ExState = false; } diff --git a/State/AThreadState.cs b/State/AThreadState.cs index 7b69d81..783f5a1 100644 --- a/State/AThreadState.cs +++ b/State/AThreadState.cs @@ -41,6 +41,9 @@ namespace ChocolArm64.State public bool Negative; public bool Running { get; set; } + public int Core { get; set; } + + private bool Interrupted; public long TpidrEl0 { get; set; } public long Tpidr { get; set; } @@ -73,6 +76,7 @@ namespace ChocolArm64.State } } + public event EventHandler Interrupt; public event EventHandler Break; public event EventHandler SvcCall; public event EventHandler Undefined; @@ -99,9 +103,26 @@ namespace ChocolArm64.State internal bool Synchronize() { + if (Interrupted) + { + Interrupted = false; + + OnInterrupt(); + } + return Running; } + internal void RequestInterrupt() + { + Interrupted = true; + } + + private void OnInterrupt() + { + Interrupt?.Invoke(this, EventArgs.Empty); + } + internal void OnBreak(long Position, int Imm) { Break?.Invoke(this, new AInstExceptionEventArgs(Position, Imm));