aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2020-12-09 19:20:05 -0300
committerGitHub <noreply@github.com>2020-12-09 19:20:05 -0300
commit48278905d1470f89be31668c738397f569af156a (patch)
tree2e35b0695b33c8eb723f5948e3f6f040d84cfe76 /Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs
parent3484265d37732b32951709e5abfa52a260db349d (diff)
Rewrite scheduler context switch code (#1786)
* Rewrite scheduler context switch code * Fix race in UnmapIpcRestorePermission * Fix thread exit issue that could leave the scheduler in a invalid state * Change context switch method to not wait on guest thread, remove spin wait, use SignalAndWait to pass control * Remove multi-core setting (it is always on now) * Re-enable assert * Remove multicore from default config and schema * Fix race in KTimeManager
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs70
1 files changed, 21 insertions, 49 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs
index b778c2a4..1d61f2f0 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs
@@ -5,21 +5,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
class KCriticalSection
{
private readonly KernelContext _context;
-
- public object LockObj { get; private set; }
-
+ private readonly object _lock;
private int _recursionCount;
+ public object Lock => _lock;
+
public KCriticalSection(KernelContext context)
{
_context = context;
-
- LockObj = new object();
+ _lock = new object();
}
public void Enter()
{
- Monitor.Enter(LockObj);
+ Monitor.Enter(_lock);
_recursionCount++;
}
@@ -31,61 +30,34 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return;
}
- bool doContextSwitch = false;
-
if (--_recursionCount == 0)
{
- if (_context.Scheduler.ThreadReselectionRequested)
- {
- _context.Scheduler.SelectThreads();
- }
+ ulong scheduledCoresMask = KScheduler.SelectThreads(_context);
- Monitor.Exit(LockObj);
+ Monitor.Exit(_lock);
- if (_context.Scheduler.MultiCoreScheduling)
+ KThread currentThread = KernelStatic.GetCurrentThread();
+ bool isCurrentThreadSchedulable = currentThread != null && currentThread.IsSchedulable;
+ if (isCurrentThreadSchedulable)
{
- lock (_context.Scheduler.CoreContexts)
- {
- for (int core = 0; core < KScheduler.CpuCoresCount; core++)
- {
- KCoreContext coreContext = _context.Scheduler.CoreContexts[core];
-
- if (coreContext.ContextSwitchNeeded)
- {
- KThread currentThread = coreContext.CurrentThread;
-
- if (currentThread == null)
- {
- // Nothing is running, we can perform the context switch immediately.
- coreContext.ContextSwitch();
- }
- else if (currentThread.IsCurrentHostThread())
- {
- // Thread running on the current core, context switch will block.
- doContextSwitch = true;
- }
- else
- {
- // Thread running on another core, request a interrupt.
- currentThread.Context.RequestInterrupt();
- }
- }
- }
- }
+ KScheduler.EnableScheduling(_context, scheduledCoresMask);
}
else
{
- doContextSwitch = true;
+ KScheduler.EnableSchedulingFromForeignThread(_context, scheduledCoresMask);
+
+ // If the thread exists but is not schedulable, we still want to suspend
+ // it if it's not runnable. That allows the kernel to still block HLE threads
+ // even if they are not scheduled on guest cores.
+ if (currentThread != null && !currentThread.IsSchedulable && currentThread.Context.Running)
+ {
+ currentThread.SchedulerWaitEvent.WaitOne();
+ }
}
}
else
{
- Monitor.Exit(LockObj);
- }
-
- if (doContextSwitch)
- {
- _context.Scheduler.ContextSwitch();
+ Monitor.Exit(_lock);
}
}
}