KSynchronization.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using Ryujinx.HLE.HOS.Kernel.Common;
  2. using System;
  3. using System.Collections.Generic;
  4. namespace Ryujinx.HLE.HOS.Kernel.Threading
  5. {
  6. class KSynchronization
  7. {
  8. private KernelContext _context;
  9. public KSynchronization(KernelContext context)
  10. {
  11. _context = context;
  12. }
  13. public KernelResult WaitFor(Span<KSynchronizationObject> syncObjs, long timeout, out int handleIndex)
  14. {
  15. handleIndex = 0;
  16. KernelResult result = KernelResult.TimedOut;
  17. _context.CriticalSection.Enter();
  18. // Check if objects are already signaled before waiting.
  19. for (int index = 0; index < syncObjs.Length; index++)
  20. {
  21. if (!syncObjs[index].IsSignaled())
  22. {
  23. continue;
  24. }
  25. handleIndex = index;
  26. _context.CriticalSection.Leave();
  27. return KernelResult.Success;
  28. }
  29. if (timeout == 0)
  30. {
  31. _context.CriticalSection.Leave();
  32. return result;
  33. }
  34. KThread currentThread = _context.Scheduler.GetCurrentThread();
  35. if (currentThread.ShallBeTerminated ||
  36. currentThread.SchedFlags == ThreadSchedState.TerminationPending)
  37. {
  38. result = KernelResult.ThreadTerminating;
  39. }
  40. else if (currentThread.SyncCancelled)
  41. {
  42. currentThread.SyncCancelled = false;
  43. result = KernelResult.Cancelled;
  44. }
  45. else
  46. {
  47. LinkedListNode<KThread>[] syncNodes = new LinkedListNode<KThread>[syncObjs.Length];
  48. for (int index = 0; index < syncObjs.Length; index++)
  49. {
  50. syncNodes[index] = syncObjs[index].AddWaitingThread(currentThread);
  51. }
  52. currentThread.WaitingSync = true;
  53. currentThread.SignaledObj = null;
  54. currentThread.ObjSyncResult = result;
  55. currentThread.Reschedule(ThreadSchedState.Paused);
  56. if (timeout > 0)
  57. {
  58. _context.TimeManager.ScheduleFutureInvocation(currentThread, timeout);
  59. }
  60. _context.CriticalSection.Leave();
  61. currentThread.WaitingSync = false;
  62. if (timeout > 0)
  63. {
  64. _context.TimeManager.UnscheduleFutureInvocation(currentThread);
  65. }
  66. _context.CriticalSection.Enter();
  67. result = currentThread.ObjSyncResult;
  68. handleIndex = -1;
  69. for (int index = 0; index < syncObjs.Length; index++)
  70. {
  71. syncObjs[index].RemoveWaitingThread(syncNodes[index]);
  72. if (syncObjs[index] == currentThread.SignaledObj)
  73. {
  74. handleIndex = index;
  75. }
  76. }
  77. }
  78. _context.CriticalSection.Leave();
  79. return result;
  80. }
  81. public void SignalObject(KSynchronizationObject syncObj)
  82. {
  83. _context.CriticalSection.Enter();
  84. if (syncObj.IsSignaled())
  85. {
  86. LinkedListNode<KThread> node = syncObj.WaitingThreads.First;
  87. while (node != null)
  88. {
  89. KThread thread = node.Value;
  90. if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
  91. {
  92. thread.SignaledObj = syncObj;
  93. thread.ObjSyncResult = KernelResult.Success;
  94. thread.Reschedule(ThreadSchedState.Running);
  95. }
  96. node = node.Next;
  97. }
  98. }
  99. _context.CriticalSection.Leave();
  100. }
  101. }
  102. }