|
|
@@ -7,6 +7,8 @@ namespace Ryujinx.Core.OsHle.Handles
|
|
|
{
|
|
|
class KProcessScheduler : IDisposable
|
|
|
{
|
|
|
+ private const int LowestPriority = 0x40;
|
|
|
+
|
|
|
private class SchedulerThread : IDisposable
|
|
|
{
|
|
|
public KThread Thread { get; private set; }
|
|
|
@@ -51,7 +53,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public SchedulerThread Pop(int MinPriority = 0x40)
|
|
|
+ public SchedulerThread Pop(int MinPriority = LowestPriority)
|
|
|
{
|
|
|
lock (Threads)
|
|
|
{
|
|
|
@@ -130,68 +132,47 @@ namespace Ryujinx.Core.OsHle.Handles
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (!ActiveProcessors.Contains(Thread.ProcessorId))
|
|
|
+ if (ActiveProcessors.Add(Thread.ProcessorId))
|
|
|
{
|
|
|
- ActiveProcessors.Add(Thread.ProcessorId);
|
|
|
-
|
|
|
Thread.Thread.Execute();
|
|
|
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} running.");
|
|
|
+ PrintDbgThreadInfo(Thread, "running.");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
WaitingToRun[Thread.ProcessorId].Push(SchedThread);
|
|
|
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(SchedThread.Thread)} waiting to run.");
|
|
|
+ PrintDbgThreadInfo(Thread, "waiting to run.");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public void Suspend(int ProcessorId)
|
|
|
+ public void RemoveThread(KThread Thread)
|
|
|
{
|
|
|
+ PrintDbgThreadInfo(Thread, "exited.");
|
|
|
+
|
|
|
lock (SchedLock)
|
|
|
{
|
|
|
- SchedulerThread SchedThread = WaitingToRun[ProcessorId].Pop();
|
|
|
+ SchedulerThread NewThread = WaitingToRun[Thread.ProcessorId].Pop();
|
|
|
|
|
|
- if (SchedThread != null)
|
|
|
- {
|
|
|
- RunThread(SchedThread);
|
|
|
- }
|
|
|
- else
|
|
|
+ if (NewThread == null)
|
|
|
{
|
|
|
- ActiveProcessors.Remove(ProcessorId);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ Logging.Debug(LogClass.KernelScheduler, $"Nothing to run on core {Thread.ProcessorId}!");
|
|
|
|
|
|
- public void Resume(KThread CurrThread)
|
|
|
- {
|
|
|
- SchedulerThread SchedThread;
|
|
|
-
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(CurrThread)} entering ipc delay wait state.");
|
|
|
-
|
|
|
- lock (SchedLock)
|
|
|
- {
|
|
|
- if (!AllThreads.TryGetValue(CurrThread, out SchedThread))
|
|
|
- {
|
|
|
- Logging.Error(LogClass.KernelScheduler, $"{GetDbgThreadInfo(CurrThread)} was not found on the scheduler queue!");
|
|
|
+ ActiveProcessors.Remove(Thread.ProcessorId);
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- TryResumingExecution(SchedThread);
|
|
|
+ RunThread(NewThread);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- public bool WaitForSignal(KThread Thread, int Timeout = -1)
|
|
|
+ public void Suspend(int ProcessorId)
|
|
|
{
|
|
|
- SchedulerThread SchedThread;
|
|
|
-
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} entering signal wait state.");
|
|
|
-
|
|
|
lock (SchedLock)
|
|
|
{
|
|
|
- SchedThread = WaitingToRun[Thread.ProcessorId].Pop();
|
|
|
+ SchedulerThread SchedThread = WaitingToRun[ProcessorId].Pop();
|
|
|
|
|
|
if (SchedThread != null)
|
|
|
{
|
|
|
@@ -199,88 +180,67 @@ namespace Ryujinx.Core.OsHle.Handles
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- ActiveProcessors.Remove(Thread.ProcessorId);
|
|
|
- }
|
|
|
-
|
|
|
- if (!AllThreads.TryGetValue(Thread, out SchedThread))
|
|
|
- {
|
|
|
- Logging.Error(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!");
|
|
|
+ Logging.Debug(LogClass.KernelScheduler, $"Nothing to run on core {ProcessorId}!");
|
|
|
|
|
|
- return false;
|
|
|
+ ActiveProcessors.Remove(ProcessorId);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- bool Result;
|
|
|
-
|
|
|
- if (Timeout >= 0)
|
|
|
- {
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} has wait timeout of {Timeout}ms.");
|
|
|
-
|
|
|
- Result = SchedThread.WaitEvent.WaitOne(Timeout);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- Result = SchedThread.WaitEvent.WaitOne();
|
|
|
- }
|
|
|
-
|
|
|
- TryResumingExecution(SchedThread);
|
|
|
-
|
|
|
- return Result;
|
|
|
}
|
|
|
|
|
|
- private void TryResumingExecution(SchedulerThread SchedThread)
|
|
|
+ public void Yield(KThread Thread)
|
|
|
{
|
|
|
- KThread Thread = SchedThread.Thread;
|
|
|
+ PrintDbgThreadInfo(Thread, "yielded execution.");
|
|
|
|
|
|
lock (SchedLock)
|
|
|
{
|
|
|
- if (ActiveProcessors.Add(Thread.ProcessorId))
|
|
|
+ SchedulerThread SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.Priority);
|
|
|
+
|
|
|
+ if (SchedThread == null)
|
|
|
{
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} resuming execution...");
|
|
|
+ PrintDbgThreadInfo(Thread, "resumed because theres nothing better to run.");
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- WaitingToRun[Thread.ProcessorId].Push(SchedThread);
|
|
|
+ RunThread(SchedThread);
|
|
|
}
|
|
|
|
|
|
- SchedThread.WaitEvent.WaitOne();
|
|
|
-
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} resuming execution...");
|
|
|
+ Resume(Thread);
|
|
|
}
|
|
|
|
|
|
- public void Yield(KThread Thread)
|
|
|
+ public void Resume(KThread Thread)
|
|
|
{
|
|
|
SchedulerThread SchedThread;
|
|
|
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} yielded execution.");
|
|
|
-
|
|
|
- lock (SchedLock)
|
|
|
+ if (!AllThreads.TryGetValue(Thread, out SchedThread))
|
|
|
{
|
|
|
- SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.Priority);
|
|
|
+ throw new InvalidOperationException();
|
|
|
+ }
|
|
|
|
|
|
- if (SchedThread == null)
|
|
|
- {
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} resumed because theres nothing better to run.");
|
|
|
+ TryResumingExecution(SchedThread);
|
|
|
+ }
|
|
|
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- RunThread(SchedThread);
|
|
|
+ private void TryResumingExecution(SchedulerThread SchedThread)
|
|
|
+ {
|
|
|
+ KThread Thread = SchedThread.Thread;
|
|
|
|
|
|
- if (!AllThreads.TryGetValue(Thread, out SchedThread))
|
|
|
+ lock (SchedLock)
|
|
|
+ {
|
|
|
+ if (ActiveProcessors.Add(Thread.ProcessorId))
|
|
|
{
|
|
|
- Logging.Error(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!");
|
|
|
+ PrintDbgThreadInfo(Thread, "resuming execution...");
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ PrintDbgThreadInfo(Thread, "entering wait state...");
|
|
|
+
|
|
|
WaitingToRun[Thread.ProcessorId].Push(SchedThread);
|
|
|
}
|
|
|
|
|
|
SchedThread.WaitEvent.WaitOne();
|
|
|
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} resuming execution...");
|
|
|
+ PrintDbgThreadInfo(Thread, "resuming execution...");
|
|
|
}
|
|
|
|
|
|
private void RunThread(SchedulerThread SchedThread)
|
|
|
@@ -291,32 +251,16 @@ namespace Ryujinx.Core.OsHle.Handles
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(SchedThread.Thread)} running.");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public void Signal(params KThread[] Threads)
|
|
|
- {
|
|
|
- lock (SchedLock)
|
|
|
- {
|
|
|
- foreach (KThread Thread in Threads)
|
|
|
- {
|
|
|
- if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
|
|
|
- {
|
|
|
- if (!WaitingToRun[Thread.ProcessorId].HasThread(SchedThread))
|
|
|
- {
|
|
|
- Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} signaled.");
|
|
|
-
|
|
|
- SchedThread.WaitEvent.Set();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ PrintDbgThreadInfo(SchedThread.Thread, "running.");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private string GetDbgThreadInfo(KThread Thread)
|
|
|
+ private void PrintDbgThreadInfo(KThread Thread, string Message)
|
|
|
{
|
|
|
- return $"Thread {Thread.ThreadId} (core {Thread.ProcessorId}) prio {Thread.Priority}";
|
|
|
+ Logging.Debug(LogClass.KernelScheduler, "(" +
|
|
|
+ "ThreadId: " + Thread.ThreadId + ", " +
|
|
|
+ "ProcessorId: " + Thread.ProcessorId + ", " +
|
|
|
+ "Priority: " + Thread.Priority + ") " + Message);
|
|
|
}
|
|
|
|
|
|
public void Dispose()
|