aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/OsHle/Kernel
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-05-15 22:36:08 -0300
committergdkchan <gab.dark.100@gmail.com>2018-05-15 22:37:54 -0300
commit73a3233d5791d85b547e9d937700e3d3d93f98ef (patch)
tree3b351d9853c3c2d18bc461b851f4950c9fe54079 /Ryujinx.Core/OsHle/Kernel
parent7a8fbcf89fb69451f4afad95eb0e8b0642e7bc8d (diff)
Fix some races in SvcThreadSync and change the way how yield works
Diffstat (limited to 'Ryujinx.Core/OsHle/Kernel')
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcHandler.cs2
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcThread.cs27
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs117
3 files changed, 70 insertions, 76 deletions
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs
index bbbd0fb0..9771bc1e 100644
--- a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs
+++ b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs
@@ -96,6 +96,8 @@ namespace Ryujinx.Core.OsHle.Kernel
Func(ThreadState);
+ Process.Scheduler.Reschedule(Process.GetThread(ThreadState.Tpidr));
+
Ns.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} ended.");
}
else
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
index f0f3d95b..b504f81a 100644
--- a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
+++ b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
@@ -55,13 +55,12 @@ namespace Ryujinx.Core.OsHle.Kernel
{
int Handle = (int)ThreadState.X0;
- KThread CurrThread = Process.HandleTable.GetData<KThread>(Handle);
+ KThread NewThread = Process.HandleTable.GetData<KThread>(Handle);
- if (CurrThread != null)
+ if (NewThread != null)
{
- Process.Scheduler.StartThread(CurrThread);
-
- Process.Scheduler.Yield(Process.GetThread(ThreadState.Tpidr));
+ Process.Scheduler.StartThread(NewThread);
+ Process.Scheduler.SetReschedule(NewThread.ProcessorId);
ThreadState.X0 = 0;
}
@@ -82,19 +81,19 @@ namespace Ryujinx.Core.OsHle.Kernel
private void SvcSleepThread(AThreadState ThreadState)
{
- ulong Ns = ThreadState.X0;
+ ulong TimeoutNs = ThreadState.X0;
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
- if (Ns == 0)
+ if (TimeoutNs == 0)
{
- Process.Scheduler.Yield(CurrThread);
+ Process.Scheduler.SetReschedule(CurrThread.ActualCore);
}
else
{
Process.Scheduler.Suspend(CurrThread);
- Thread.Sleep(NsTimeConverter.GetTimeMs(Ns));
+ Thread.Sleep(NsTimeConverter.GetTimeMs(TimeoutNs));
Process.Scheduler.Resume(CurrThread);
}
@@ -210,15 +209,7 @@ namespace Ryujinx.Core.OsHle.Kernel
Thread.CoreMask = (int)CoreMask;
- KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
-
- //Try yielding execution, for the case where the new
- //core mask allows the thread to run on the current core.
- Process.Scheduler.Yield(CurrThread);
-
- //Try running the modified thread, for the case where one
- //of the cores specified on the core mask is free.
- Process.Scheduler.TryRunning(Thread);
+ Process.Scheduler.TryToRun(Thread);
ThreadState.X0 = 0;
}
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs
index f9e035ad..1d28a24b 100644
--- a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs
+++ b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs
@@ -96,10 +96,7 @@ namespace Ryujinx.Core.OsHle.Kernel
return;
}
- if (MutexUnlock(Process.GetThread(ThreadState.Tpidr), MutexAddress))
- {
- Process.Scheduler.Yield(Process.GetThread(ThreadState.Tpidr));
- }
+ MutexUnlock(Process.GetThread(ThreadState.Tpidr), MutexAddress);
ThreadState.X0 = 0;
}
@@ -157,8 +154,6 @@ namespace Ryujinx.Core.OsHle.Kernel
return;
}
- Process.Scheduler.Yield(Process.GetThread(ThreadState.Tpidr));
-
ThreadState.X0 = 0;
}
@@ -167,7 +162,13 @@ namespace Ryujinx.Core.OsHle.Kernel
long CondVarAddress = (long)ThreadState.X0;
int Count = (int)ThreadState.X1;
- CondVarSignal(CondVarAddress, Count);
+ Ns.Log.PrintDebug(LogClass.KernelSvc,
+ "CondVarAddress = " + CondVarAddress.ToString("x16") + ", " +
+ "Count = " + Count .ToString("x8"));
+
+ KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+
+ CondVarSignal(CurrThread, CondVarAddress, Count);
ThreadState.X0 = 0;
}
@@ -179,12 +180,12 @@ namespace Ryujinx.Core.OsHle.Kernel
int WaitThreadHandle,
long MutexAddress)
{
- int MutexValue = Process.Memory.ReadInt32(MutexAddress);
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8"));
-
lock (Process.ThreadSyncLock)
{
+ int MutexValue = Process.Memory.ReadInt32(MutexAddress);
+
+ Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8"));
+
if (MutexValue != (OwnerThreadHandle | MutexHasListenersMask))
{
return;
@@ -201,20 +202,13 @@ namespace Ryujinx.Core.OsHle.Kernel
Process.Scheduler.EnterWait(CurrThread);
}
- private bool MutexUnlock(KThread CurrThread, long MutexAddress)
+ private void MutexUnlock(KThread CurrThread, long MutexAddress)
{
- if (CurrThread == null)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex 0x{MutexAddress:x16}!");
-
- return false;
- }
-
lock (Process.ThreadSyncLock)
{
//This is the new thread that will not own the mutex.
//If no threads are waiting for the lock, then it should be null.
- KThread OwnerThread = GetHighestPriority(CurrThread.MutexWaiters, MutexAddress);
+ KThread OwnerThread = PopThread(CurrThread.MutexWaiters, x => x.MutexAddress == MutexAddress);
if (OwnerThread != null)
{
@@ -240,16 +234,12 @@ namespace Ryujinx.Core.OsHle.Kernel
Process.Scheduler.WakeUp(OwnerThread);
Ns.Log.PrintDebug(LogClass.KernelSvc, "Gave mutex to thread id " + OwnerThread.ThreadId + "!");
-
- return true;
}
else
{
Process.Memory.WriteInt32(MutexAddress, 0);
Ns.Log.PrintDebug(LogClass.KernelSvc, "No threads waiting mutex!");
-
- return false;
}
}
}
@@ -265,8 +255,10 @@ namespace Ryujinx.Core.OsHle.Kernel
WaitThread.MutexAddress = MutexAddress;
WaitThread.CondVarAddress = CondVarAddress;
- lock (Process.ThreadArbiterListLock)
+ lock (Process.ThreadArbiterList)
{
+ WaitThread.CondVarSignaled = false;
+
Process.ThreadArbiterList.Add(WaitThread);
}
@@ -274,58 +266,77 @@ namespace Ryujinx.Core.OsHle.Kernel
if (Timeout != ulong.MaxValue)
{
- return Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout));
+ Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout));
+
+ lock (Process.ThreadArbiterList)
+ {
+ if (!WaitThread.CondVarSignaled)
+ {
+ Process.ThreadArbiterList.Remove(WaitThread);
+
+ return false;
+ }
+ }
}
else
{
Process.Scheduler.EnterWait(WaitThread);
-
- return true;
}
+
+ return true;
}
- private void CondVarSignal(long CondVarAddress, int Count)
+ private void CondVarSignal(KThread CurrThread, long CondVarAddress, int Count)
{
- lock (Process.ThreadArbiterListLock)
+ lock (Process.ThreadArbiterList)
{
- KThread CurrThread = GetHighestPriority(CondVarAddress);
-
- while (CurrThread != null && (Count == -1 || Count-- > 0))
+ while (Count == -1 || Count-- > 0)
{
- AcquireMutexValue(CurrThread.MutexAddress);
+ KThread WaitThread = PopThread(Process.ThreadArbiterList, x => x.CondVarAddress == CondVarAddress);
+
+ if (WaitThread == null)
+ {
+ Ns.Log.PrintDebug(LogClass.KernelSvc, "No more threads to wake up!");
+
+ break;
+ }
- int MutexValue = Process.Memory.ReadInt32(CurrThread.MutexAddress);
+ WaitThread.CondVarSignaled = true;
+
+ AcquireMutexValue(WaitThread.MutexAddress);
+
+ int MutexValue = Process.Memory.ReadInt32(WaitThread.MutexAddress);
+
+ Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8"));
if (MutexValue == 0)
{
//Give the lock to this thread.
- Process.Memory.WriteInt32(CurrThread.MutexAddress, CurrThread.WaitHandle);
+ Process.Memory.WriteInt32(WaitThread.MutexAddress, WaitThread.WaitHandle);
- CurrThread.WaitHandle = 0;
- CurrThread.MutexAddress = 0;
- CurrThread.CondVarAddress = 0;
+ WaitThread.WaitHandle = 0;
+ WaitThread.MutexAddress = 0;
+ WaitThread.CondVarAddress = 0;
- CurrThread.MutexOwner?.UpdatePriority();
+ WaitThread.MutexOwner?.UpdatePriority();
- CurrThread.MutexOwner = null;
+ WaitThread.MutexOwner = null;
- Process.Scheduler.WakeUp(CurrThread);
+ Process.Scheduler.WakeUp(WaitThread);
}
else
{
//Wait until the lock is released.
MutexValue &= ~MutexHasListenersMask;
- InsertWaitingMutexThread(MutexValue, CurrThread);
+ InsertWaitingMutexThread(MutexValue, WaitThread);
MutexValue |= MutexHasListenersMask;
- Process.Memory.WriteInt32(CurrThread.MutexAddress, MutexValue);
+ Process.Memory.WriteInt32(WaitThread.MutexAddress, MutexValue);
}
- ReleaseMutexValue(CurrThread.MutexAddress);
-
- CurrThread = GetHighestPriority(CondVarAddress);
+ ReleaseMutexValue(WaitThread.MutexAddress);
}
}
}
@@ -381,17 +392,7 @@ namespace Ryujinx.Core.OsHle.Kernel
}
}
- private KThread GetHighestPriority(List<KThread> Threads, long MutexAddress)
- {
- return GetHighestPriority(Threads, x => x.MutexAddress == MutexAddress);
- }
-
- private KThread GetHighestPriority(long CondVarAddress)
- {
- return GetHighestPriority(Process.ThreadArbiterList, x => x.CondVarAddress == CondVarAddress);
- }
-
- private KThread GetHighestPriority(List<KThread> Threads, Func<KThread, bool> Predicate)
+ private KThread PopThread(List<KThread> Threads, Func<KThread, bool> Predicate)
{
KThread Thread = Threads.OrderBy(x => x.ActualPriority).FirstOrDefault(Predicate);