KSynchronization.cs 3.8 KB

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