Ensure that writes to the mutex address clears the exclusive monitor

This commit is contained in:
gdkchan 2018-06-21 22:32:13 -03:00
commit 9f3eb06c61
2 changed files with 34 additions and 11 deletions

View file

@ -131,6 +131,24 @@ namespace ChocolArm64.Memory
} }
} }
public void WriteInt32ToSharedAddr(long Position, int Value)
{
long MaskedPosition = Position & ~ErgMask;
lock (Monitors)
{
foreach (ArmMonitor Mon in Monitors.Values)
{
if (Mon.Position == MaskedPosition && Mon.ExState)
{
Mon.ExState = false;
}
}
WriteInt32(Position, Value);
}
}
public long GetHostPageSize() public long GetHostPageSize()
{ {
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))

View file

@ -1,6 +1,7 @@
using ChocolArm64.State; using ChocolArm64.State;
using Ryujinx.HLE.Logging; using Ryujinx.HLE.Logging;
using Ryujinx.HLE.OsHle.Handles; using Ryujinx.HLE.OsHle.Handles;
using System;
using static Ryujinx.HLE.OsHle.ErrorCode; using static Ryujinx.HLE.OsHle.ErrorCode;
@ -139,9 +140,9 @@ namespace Ryujinx.HLE.OsHle.Kernel
return; return;
} }
KThread CurrThread = Process.GetThread(ThreadState.Tpidr); KThread WaitThread = Process.GetThread(ThreadState.Tpidr);
if (!CondVarWait(CurrThread, ThreadHandle, MutexAddress, CondVarAddress, Timeout)) if (!CondVarWait(WaitThread, ThreadHandle, MutexAddress, CondVarAddress, Timeout))
{ {
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
@ -176,7 +177,7 @@ namespace Ryujinx.HLE.OsHle.Kernel
{ {
lock (Process.ThreadSyncLock) lock (Process.ThreadSyncLock)
{ {
int MutexValue = Process.Memory.ReadInt32(MutexAddress); int MutexValue = Memory.ReadInt32(MutexAddress);
Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8")); Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8"));
@ -204,6 +205,11 @@ namespace Ryujinx.HLE.OsHle.Kernel
//If no threads are waiting for the lock, then it should be null. //If no threads are waiting for the lock, then it should be null.
(KThread OwnerThread, int Count) = PopMutexThreadUnsafe(CurrThread, MutexAddress); (KThread OwnerThread, int Count) = PopMutexThreadUnsafe(CurrThread, MutexAddress);
if (OwnerThread == CurrThread)
{
throw new InvalidOperationException();
}
if (OwnerThread != null) if (OwnerThread != null)
{ {
//Remove all waiting mutex from the old owner, //Remove all waiting mutex from the old owner,
@ -214,13 +220,12 @@ namespace Ryujinx.HLE.OsHle.Kernel
int HasListeners = Count >= 2 ? MutexHasListenersMask : 0; int HasListeners = Count >= 2 ? MutexHasListenersMask : 0;
Process.Memory.WriteInt32(MutexAddress, HasListeners | OwnerThread.WaitHandle); Memory.WriteInt32ToSharedAddr(MutexAddress, HasListeners | OwnerThread.WaitHandle);
OwnerThread.WaitHandle = 0; OwnerThread.WaitHandle = 0;
OwnerThread.MutexAddress = 0; OwnerThread.MutexAddress = 0;
OwnerThread.CondVarAddress = 0; OwnerThread.CondVarAddress = 0;
OwnerThread.MutexOwner = null;
OwnerThread.MutexOwner = null;
OwnerThread.UpdatePriority(); OwnerThread.UpdatePriority();
@ -230,7 +235,7 @@ namespace Ryujinx.HLE.OsHle.Kernel
} }
else else
{ {
Process.Memory.WriteInt32(MutexAddress, 0); Memory.WriteInt32ToSharedAddr(MutexAddress, 0);
Ns.Log.PrintDebug(LogClass.KernelSvc, "No threads waiting mutex!"); Ns.Log.PrintDebug(LogClass.KernelSvc, "No threads waiting mutex!");
} }
@ -316,7 +321,7 @@ namespace Ryujinx.HLE.OsHle.Kernel
Memory.SetExclusive(ThreadState, MutexAddress); Memory.SetExclusive(ThreadState, MutexAddress);
int MutexValue = Process.Memory.ReadInt32(MutexAddress); int MutexValue = Memory.ReadInt32(MutexAddress);
while (MutexValue != 0) while (MutexValue != 0)
{ {
@ -325,7 +330,7 @@ namespace Ryujinx.HLE.OsHle.Kernel
//Wait until the lock is released. //Wait until the lock is released.
InsertWaitingMutexThreadUnsafe(MutexValue & ~MutexHasListenersMask, WaitThread); InsertWaitingMutexThreadUnsafe(MutexValue & ~MutexHasListenersMask, WaitThread);
Process.Memory.WriteInt32(MutexAddress, MutexValue | MutexHasListenersMask); Memory.WriteInt32(MutexAddress, MutexValue | MutexHasListenersMask);
Memory.ClearExclusiveForStore(ThreadState); Memory.ClearExclusiveForStore(ThreadState);
@ -334,7 +339,7 @@ namespace Ryujinx.HLE.OsHle.Kernel
Memory.SetExclusive(ThreadState, MutexAddress); Memory.SetExclusive(ThreadState, MutexAddress);
MutexValue = Process.Memory.ReadInt32(MutexAddress); MutexValue = Memory.ReadInt32(MutexAddress);
} }
Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8")); Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8"));
@ -342,7 +347,7 @@ namespace Ryujinx.HLE.OsHle.Kernel
if (MutexValue == 0) if (MutexValue == 0)
{ {
//Give the lock to this thread. //Give the lock to this thread.
Process.Memory.WriteInt32(MutexAddress, WaitThread.WaitHandle); Memory.WriteInt32ToSharedAddr(MutexAddress, WaitThread.WaitHandle);
WaitThread.WaitHandle = 0; WaitThread.WaitHandle = 0;
WaitThread.MutexAddress = 0; WaitThread.MutexAddress = 0;