aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/OsHle/Handles
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/Handles
parent7a8fbcf89fb69451f4afad95eb0e8b0642e7bc8d (diff)
Fix some races in SvcThreadSync and change the way how yield works
Diffstat (limited to 'Ryujinx.Core/OsHle/Handles')
-rw-r--r--Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs210
-rw-r--r--Ryujinx.Core/OsHle/Handles/KThread.cs18
-rw-r--r--Ryujinx.Core/OsHle/Handles/SchedulerThread.cs2
3 files changed, 97 insertions, 133 deletions
diff --git a/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs
index 487a8147..f27455b9 100644
--- a/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs
+++ b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs
@@ -1,6 +1,7 @@
using Ryujinx.Core.Logging;
using System;
using System.Collections.Concurrent;
+using System.Threading;
namespace Ryujinx.Core.OsHle.Handles
{
@@ -10,7 +11,7 @@ namespace Ryujinx.Core.OsHle.Handles
private ThreadQueue WaitingToRun;
- private int ActiveCores;
+ private KThread[] CoreThreads;
private object SchedLock;
@@ -24,6 +25,8 @@ namespace Ryujinx.Core.OsHle.Handles
WaitingToRun = new ThreadQueue();
+ CoreThreads = new KThread[4];
+
SchedLock = new object();
}
@@ -38,7 +41,7 @@ namespace Ryujinx.Core.OsHle.Handles
return;
}
- if (AddActiveCore(Thread))
+ if (TryAddToCore(Thread))
{
Thread.Thread.Execute();
@@ -74,7 +77,7 @@ namespace Ryujinx.Core.OsHle.Handles
{
Log.PrintDebug(LogClass.KernelScheduler, $"Nothing to run on core {ActualCore}!");
- RemoveActiveCore(ActualCore);
+ CoreThreads[ActualCore] = null;
return;
}
@@ -104,44 +107,38 @@ namespace Ryujinx.Core.OsHle.Handles
}
}
- public void EnterWait(KThread Thread)
+ public void EnterWait(KThread Thread, int TimeoutMs = Timeout.Infinite)
{
- if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
- {
- throw new InvalidOperationException();
- }
+ SchedulerThread SchedThread = AllThreads[Thread];
Suspend(Thread);
- SchedThread.WaitSync.WaitOne();
+ SchedThread.WaitSync.WaitOne(TimeoutMs);
TryResumingExecution(SchedThread);
}
- public bool EnterWait(KThread Thread, int Timeout)
+ public void WakeUp(KThread Thread)
{
- if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
- {
- throw new InvalidOperationException();
- }
-
- Suspend(Thread);
-
- bool Result = SchedThread.WaitSync.WaitOne(Timeout);
-
- TryResumingExecution(SchedThread);
-
- return Result;
+ AllThreads[Thread].WaitSync.Set();
}
- public void WakeUp(KThread Thread)
+ public void TryToRun(KThread Thread)
{
- if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
+ lock (SchedLock)
{
- throw new InvalidOperationException();
+ if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
+ {
+ if (WaitingToRun.HasThread(SchedThread) && TryAddToCore(Thread))
+ {
+ RunThread(SchedThread);
+ }
+ else
+ {
+ SetReschedule(Thread.ProcessorId);
+ }
+ }
}
-
- SchedThread.WaitSync.Set();
}
public void Suspend(KThread Thread)
@@ -150,6 +147,8 @@ namespace Ryujinx.Core.OsHle.Handles
{
PrintDbgThreadInfo(Thread, "suspended.");
+ AllThreads[Thread].NeedsReschedule = false;
+
int ActualCore = Thread.ActualCore;
SchedulerThread SchedThread = WaitingToRun.Pop(ActualCore);
@@ -158,84 +157,76 @@ namespace Ryujinx.Core.OsHle.Handles
{
SchedThread.Thread.ActualCore = ActualCore;
+ CoreThreads[ActualCore] = SchedThread.Thread;
+
RunThread(SchedThread);
}
else
{
Log.PrintDebug(LogClass.KernelScheduler, $"Nothing to run on core {Thread.ActualCore}!");
- RemoveActiveCore(ActualCore);
+ CoreThreads[ActualCore] = null;
+ }
+ }
+ }
+
+ public void SetReschedule(int Core)
+ {
+ lock (SchedLock)
+ {
+ KThread Thread = CoreThreads[Core];
+
+ if (Thread != null && AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
+ {
+ SchedThread.NeedsReschedule = true;
}
}
}
- public void Yield(KThread Thread)
+ public void Reschedule(KThread Thread)
{
- PrintDbgThreadInfo(Thread, "yielded execution.");
+ SchedulerThread SchedThread = AllThreads[Thread];
- if (IsActive(Thread))
+ bool NeedsReschedule;
+
+ lock (SchedLock)
{
+ NeedsReschedule = SchedThread.NeedsReschedule;
+
+ SchedThread.NeedsReschedule = false;
+ }
+
+ if (NeedsReschedule)
+ {
+ PrintDbgThreadInfo(Thread, "yielded execution.");
+
lock (SchedLock)
{
int ActualCore = Thread.ActualCore;
- SchedulerThread SchedThread = WaitingToRun.Pop(ActualCore, Thread.ActualPriority);
+ SchedulerThread NewThread = WaitingToRun.Pop(ActualCore, Thread.ActualPriority);
- if (SchedThread == null)
+ if (NewThread == null)
{
PrintDbgThreadInfo(Thread, "resumed because theres nothing better to run.");
return;
}
- if (SchedThread != null)
- {
- SchedThread.Thread.ActualCore = ActualCore;
-
- RunThread(SchedThread);
- }
- }
- }
- else
- {
- //Just stop running the thread if it's not active,
- //and run whatever is waiting to run with the higuest priority.
- Suspend(Thread);
- }
-
- Resume(Thread);
- }
+ NewThread.Thread.ActualCore = ActualCore;
- public bool TryRunning(KThread Thread)
- {
- //Failing to get the thread here is fine,
- //the thread may not have been started yet.
- if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
- {
- lock (SchedLock)
- {
- if (WaitingToRun.HasThread(SchedThread) && AddActiveCore(Thread))
- {
- WaitingToRun.Remove(SchedThread);
-
- RunThread(SchedThread);
+ CoreThreads[ActualCore] = NewThread.Thread;
- return true;
- }
+ RunThread(NewThread);
}
- }
- return false;
+ TryResumingExecution(SchedThread);
+ }
}
public void Resume(KThread Thread)
{
- if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
- {
- throw new InvalidOperationException();
- }
-
- TryResumingExecution(SchedThread);
+ TryResumingExecution(AllThreads[Thread]);
}
private void TryResumingExecution(SchedulerThread SchedThread)
@@ -248,7 +239,7 @@ namespace Ryujinx.Core.OsHle.Handles
lock (SchedLock)
{
- if (AddActiveCore(Thread))
+ if (TryAddToCore(Thread))
{
PrintDbgThreadInfo(Thread, "resuming execution...");
@@ -257,6 +248,8 @@ namespace Ryujinx.Core.OsHle.Handles
WaitingToRun.Push(SchedThread);
+ SetReschedule(Thread.ProcessorId);
+
PrintDbgThreadInfo(Thread, "entering wait state...");
}
@@ -287,71 +280,36 @@ namespace Ryujinx.Core.OsHle.Handles
}
}
- private bool IsActive(KThread Thread)
- {
- if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
- {
- throw new InvalidOperationException();
- }
-
- return SchedThread.IsActive;
- }
-
- private bool AddActiveCore(KThread Thread)
+ private bool TryAddToCore(KThread Thread)
{
- int CoreMask;
+ //First, try running it on Ideal Core.
+ int IdealCore = Thread.IdealCore;
- lock (SchedLock)
+ if (IdealCore != -1 && CoreThreads[IdealCore] == null)
{
- //First, try running it on Ideal Core.
- int IdealCore = Thread.IdealCore;
+ Thread.ActualCore = IdealCore;
- if (IdealCore != -1)
- {
- CoreMask = 1 << IdealCore;
-
- if ((ActiveCores & CoreMask) == 0)
- {
- ActiveCores |= CoreMask;
+ CoreThreads[IdealCore] = Thread;
- Thread.ActualCore = IdealCore;
-
- return true;
- }
- }
+ return true;
+ }
- //If that fails, then try running on any core allowed by Core Mask.
- CoreMask = Thread.CoreMask & ~ActiveCores;
+ //If that fails, then try running on any core allowed by Core Mask.
+ int CoreMask = Thread.CoreMask;
- if (CoreMask != 0)
+ for (int Core = 0; Core < CoreThreads.Length; Core++, CoreMask >>= 1)
+ {
+ if ((CoreMask & 1) != 0 && CoreThreads[Core] == null)
{
- CoreMask &= -CoreMask;
+ Thread.ActualCore = Core;
- ActiveCores |= CoreMask;
-
- for (int Bit = 0; Bit < 32; Bit++)
- {
- if (((CoreMask >> Bit) & 1) != 0)
- {
- Thread.ActualCore = Bit;
+ CoreThreads[Core] = Thread;
- return true;
- }
- }
-
- throw new InvalidOperationException();
+ return true;
}
-
- return false;
}
- }
- private void RemoveActiveCore(int Core)
- {
- lock (SchedLock)
- {
- ActiveCores &= ~(1 << Core);
- }
+ return false;
}
private void PrintDbgThreadInfo(KThread Thread, string Message)
diff --git a/Ryujinx.Core/OsHle/Handles/KThread.cs b/Ryujinx.Core/OsHle/Handles/KThread.cs
index ce9c3db2..48782823 100644
--- a/Ryujinx.Core/OsHle/Handles/KThread.cs
+++ b/Ryujinx.Core/OsHle/Handles/KThread.cs
@@ -12,6 +12,8 @@ namespace Ryujinx.Core.OsHle.Handles
public long MutexAddress { get; set; }
public long CondVarAddress { get; set; }
+ public bool CondVarSignaled { get; set; }
+
private Process Process;
public List<KThread> MutexWaiters { get; private set; }
@@ -21,8 +23,9 @@ namespace Ryujinx.Core.OsHle.Handles
public int ActualPriority { get; private set; }
public int WantedPriority { get; private set; }
- public int ActualCore { get; set; }
- public int IdealCore { get; set; }
+ public int ActualCore { get; set; }
+ public int ProcessorId { get; set; }
+ public int IdealCore { get; set; }
public int WaitHandle { get; set; }
@@ -31,16 +34,17 @@ namespace Ryujinx.Core.OsHle.Handles
public KThread(
AThread Thread,
Process Process,
- int IdealCore,
+ int ProcessorId,
int Priority)
{
- this.Thread = Thread;
- this.Process = Process;
- this.IdealCore = IdealCore;
+ this.Thread = Thread;
+ this.Process = Process;
+ this.ProcessorId = ProcessorId;
+ this.IdealCore = ProcessorId;
MutexWaiters = new List<KThread>();
- CoreMask = 1 << IdealCore;
+ CoreMask = 1 << ProcessorId;
ActualPriority = WantedPriority = Priority;
}
diff --git a/Ryujinx.Core/OsHle/Handles/SchedulerThread.cs b/Ryujinx.Core/OsHle/Handles/SchedulerThread.cs
index 4a8b4c09..dd79b0f7 100644
--- a/Ryujinx.Core/OsHle/Handles/SchedulerThread.cs
+++ b/Ryujinx.Core/OsHle/Handles/SchedulerThread.cs
@@ -11,6 +11,8 @@ namespace Ryujinx.Core.OsHle.Handles
public bool IsActive { get; set; }
+ public bool NeedsReschedule { get; set; }
+
public AutoResetEvent WaitSync { get; private set; }
public ManualResetEvent WaitActivity { get; private set; }
public AutoResetEvent WaitSched { get; private set; }