mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-08-20 07:38:42 +02:00
* 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
64 lines
1.9 KiB
C#
64 lines
1.9 KiB
C#
using System.Threading;
|
|
|
|
namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|
{
|
|
class KCriticalSection
|
|
{
|
|
private readonly KernelContext _context;
|
|
private readonly object _lock;
|
|
private int _recursionCount;
|
|
|
|
public object Lock => _lock;
|
|
|
|
public KCriticalSection(KernelContext context)
|
|
{
|
|
_context = context;
|
|
_lock = new object();
|
|
}
|
|
|
|
public void Enter()
|
|
{
|
|
Monitor.Enter(_lock);
|
|
|
|
_recursionCount++;
|
|
}
|
|
|
|
public void Leave()
|
|
{
|
|
if (_recursionCount == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (--_recursionCount == 0)
|
|
{
|
|
ulong scheduledCoresMask = KScheduler.SelectThreads(_context);
|
|
|
|
Monitor.Exit(_lock);
|
|
|
|
KThread currentThread = KernelStatic.GetCurrentThread();
|
|
bool isCurrentThreadSchedulable = currentThread != null && currentThread.IsSchedulable;
|
|
if (isCurrentThreadSchedulable)
|
|
{
|
|
KScheduler.EnableScheduling(_context, scheduledCoresMask);
|
|
}
|
|
else
|
|
{
|
|
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(_lock);
|
|
}
|
|
}
|
|
}
|
|
} |