2018-09-19 00:36:43 +01:00
|
|
|
using System.Threading;
|
|
|
|
|
2018-12-18 05:33:36 +00:00
|
|
|
namespace Ryujinx.HLE.HOS.Kernel.Threading
|
2018-09-19 00:36:43 +01:00
|
|
|
{
|
2018-11-28 22:18:09 +00:00
|
|
|
class KCriticalSection
|
2018-09-19 00:36:43 +01:00
|
|
|
{
|
2020-05-04 04:41:29 +01:00
|
|
|
private readonly KernelContext _context;
|
2020-12-09 22:20:05 +00:00
|
|
|
private readonly object _lock;
|
2018-12-06 11:16:24 +00:00
|
|
|
private int _recursionCount;
|
2018-09-19 00:36:43 +01:00
|
|
|
|
2020-12-09 22:20:05 +00:00
|
|
|
public object Lock => _lock;
|
|
|
|
|
2020-05-04 04:41:29 +01:00
|
|
|
public KCriticalSection(KernelContext context)
|
2018-09-19 00:36:43 +01:00
|
|
|
{
|
2020-05-04 04:41:29 +01:00
|
|
|
_context = context;
|
2020-12-09 22:20:05 +00:00
|
|
|
_lock = new object();
|
2018-09-19 00:36:43 +01:00
|
|
|
}
|
|
|
|
|
2018-11-28 22:18:09 +00:00
|
|
|
public void Enter()
|
2018-09-19 00:36:43 +01:00
|
|
|
{
|
2020-12-09 22:20:05 +00:00
|
|
|
Monitor.Enter(_lock);
|
2018-09-19 00:36:43 +01:00
|
|
|
|
2018-12-06 11:16:24 +00:00
|
|
|
_recursionCount++;
|
2018-09-19 00:36:43 +01:00
|
|
|
}
|
|
|
|
|
2018-11-28 22:18:09 +00:00
|
|
|
public void Leave()
|
2018-09-19 00:36:43 +01:00
|
|
|
{
|
2018-12-06 11:16:24 +00:00
|
|
|
if (_recursionCount == 0)
|
2018-09-19 00:36:43 +01:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-12-06 11:16:24 +00:00
|
|
|
if (--_recursionCount == 0)
|
2018-09-19 00:36:43 +01:00
|
|
|
{
|
2020-12-09 22:20:05 +00:00
|
|
|
ulong scheduledCoresMask = KScheduler.SelectThreads(_context);
|
2018-09-19 00:36:43 +01:00
|
|
|
|
2020-12-09 22:20:05 +00:00
|
|
|
Monitor.Exit(_lock);
|
2018-09-19 00:36:43 +01:00
|
|
|
|
2020-12-09 22:20:05 +00:00
|
|
|
KThread currentThread = KernelStatic.GetCurrentThread();
|
|
|
|
bool isCurrentThreadSchedulable = currentThread != null && currentThread.IsSchedulable;
|
|
|
|
if (isCurrentThreadSchedulable)
|
2018-09-19 00:36:43 +01:00
|
|
|
{
|
2020-12-09 22:20:05 +00:00
|
|
|
KScheduler.EnableScheduling(_context, scheduledCoresMask);
|
2018-09-19 00:36:43 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-12-09 22:20:05 +00:00
|
|
|
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();
|
|
|
|
}
|
2018-09-19 00:36:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-12-09 22:20:05 +00:00
|
|
|
Monitor.Exit(_lock);
|
2018-09-19 00:36:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|