From 3e6afeb5134fc699158e8c4d1646a138a947a93d Mon Sep 17 00:00:00 2001 From: gdkchan Date: Thu, 21 Jun 2018 23:05:42 -0300 Subject: Fix some thread sync issues (#172) * Fix some thread sync issues * Remove some debug stuff * Ensure that writes to the mutex address clears the exclusive monitor --- ChocolArm64/Memory/AMemory.cs | 111 +++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 55 deletions(-) (limited to 'ChocolArm64/Memory') diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs index fe250d4b..c02bf172 100644 --- a/ChocolArm64/Memory/AMemory.cs +++ b/ChocolArm64/Memory/AMemory.cs @@ -6,6 +6,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +using System.Threading; namespace ChocolArm64.Memory { @@ -15,32 +16,18 @@ namespace ChocolArm64.Memory public AMemoryMgr Manager { get; private set; } - private struct ExMonitor + private class ArmMonitor { - public long Position { get; private set; } - - private bool ExState; - - public ExMonitor(long Position, bool ExState) - { - this.Position = Position; - this.ExState = ExState; - } + public long Position; + public bool ExState; public bool HasExclusiveAccess(long Position) { return this.Position == Position && ExState; } - - public void Reset() - { - ExState = false; - } } - private Dictionary Monitors; - - private HashSet ExAddrs; + private Dictionary Monitors; public IntPtr Ram { get; private set; } @@ -50,9 +37,7 @@ namespace ChocolArm64.Memory { Manager = new AMemoryMgr(); - Monitors = new Dictionary(); - - ExAddrs = new HashSet(); + Monitors = new Dictionary(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -66,16 +51,13 @@ namespace ChocolArm64.Memory RamPtr = (byte*)Ram; } - public void RemoveMonitor(int ThreadId) + public void RemoveMonitor(AThreadState State) { lock (Monitors) { - if (Monitors.TryGetValue(ThreadId, out ExMonitor Monitor)) - { - ExAddrs.Remove(Monitor.Position); - } + ClearExclusive(State); - Monitors.Remove(ThreadId); + Monitors.Remove(State.ThreadId); } } @@ -85,66 +67,85 @@ namespace ChocolArm64.Memory lock (Monitors) { - if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) + foreach (ArmMonitor Mon in Monitors.Values) { - ExAddrs.Remove(Monitor.Position); + if (Mon.Position == Position && Mon.ExState) + { + Mon.ExState = false; + } } - bool ExState = ExAddrs.Add(Position); - - Monitor = new ExMonitor(Position, ExState); - - if (!Monitors.TryAdd(ThreadState.ThreadId, Monitor)) + if (!Monitors.TryGetValue(ThreadState.ThreadId, out ArmMonitor ThreadMon)) { - Monitors[ThreadState.ThreadId] = Monitor; + ThreadMon = new ArmMonitor(); + + Monitors.Add(ThreadState.ThreadId, ThreadMon); } + + ThreadMon.Position = Position; + ThreadMon.ExState = true; } } public bool TestExclusive(AThreadState ThreadState, long Position) { + //Note: Any call to this method also should be followed by a + //call to ClearExclusiveForStore if this method returns true. Position &= ~ErgMask; - lock (Monitors) + Monitor.Enter(Monitors); + + if (!Monitors.TryGetValue(ThreadState.ThreadId, out ArmMonitor ThreadMon)) { - if (!Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) - { - return false; - } + return false; + } + + bool ExState = ThreadMon.HasExclusiveAccess(Position); - return Monitor.HasExclusiveAccess(Position); + if (!ExState) + { + Monitor.Exit(Monitors); } + + return ExState; } - public void ClearExclusive(AThreadState ThreadState) + public void ClearExclusiveForStore(AThreadState ThreadState) { - lock (Monitors) + if (Monitors.TryGetValue(ThreadState.ThreadId, out ArmMonitor ThreadMon)) { - if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) - { - Monitor.Reset(); - ExAddrs.Remove(Monitor.Position); - } + ThreadMon.ExState = false; } + + Monitor.Exit(Monitors); } - public bool AcquireAddress(long Position) + public void ClearExclusive(AThreadState ThreadState) { - Position &= ~ErgMask; - lock (Monitors) { - return ExAddrs.Add(Position); + if (Monitors.TryGetValue(ThreadState.ThreadId, out ArmMonitor ThreadMon)) + { + ThreadMon.ExState = false; + } } } - public void ReleaseAddress(long Position) + public void WriteInt32ToSharedAddr(long Position, int Value) { - Position &= ~ErgMask; + long MaskedPosition = Position & ~ErgMask; lock (Monitors) { - ExAddrs.Remove(Position); + foreach (ArmMonitor Mon in Monitors.Values) + { + if (Mon.Position == MaskedPosition && Mon.ExState) + { + Mon.ExState = false; + } + } + + WriteInt32(Position, Value); } } -- cgit v1.2.3