diff options
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs')
-rw-r--r-- | src/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs new file mode 100644 index 00000000..1d61f2f0 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs @@ -0,0 +1,64 @@ +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); + } + } + } +}
\ No newline at end of file |