KCriticalSection.cs 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. using System.Threading;
  2. namespace Ryujinx.HLE.HOS.Kernel.Threading
  3. {
  4. class KCriticalSection
  5. {
  6. private readonly KernelContext _context;
  7. private readonly object _lock;
  8. private int _recursionCount;
  9. public object Lock => _lock;
  10. public KCriticalSection(KernelContext context)
  11. {
  12. _context = context;
  13. _lock = new object();
  14. }
  15. public void Enter()
  16. {
  17. Monitor.Enter(_lock);
  18. _recursionCount++;
  19. }
  20. public void Leave()
  21. {
  22. if (_recursionCount == 0)
  23. {
  24. return;
  25. }
  26. if (--_recursionCount == 0)
  27. {
  28. ulong scheduledCoresMask = KScheduler.SelectThreads(_context);
  29. Monitor.Exit(_lock);
  30. KThread currentThread = KernelStatic.GetCurrentThread();
  31. bool isCurrentThreadSchedulable = currentThread != null && currentThread.IsSchedulable;
  32. if (isCurrentThreadSchedulable)
  33. {
  34. KScheduler.EnableScheduling(_context, scheduledCoresMask);
  35. }
  36. else
  37. {
  38. KScheduler.EnableSchedulingFromForeignThread(_context, scheduledCoresMask);
  39. // If the thread exists but is not schedulable, we still want to suspend
  40. // it if it's not runnable. That allows the kernel to still block HLE threads
  41. // even if they are not scheduled on guest cores.
  42. if (currentThread != null && !currentThread.IsSchedulable && currentThread.Context.Running)
  43. {
  44. currentThread.SchedulerWaitEvent.WaitOne();
  45. }
  46. }
  47. }
  48. else
  49. {
  50. Monitor.Exit(_lock);
  51. }
  52. }
  53. }
  54. }