CondVar.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using Ryujinx.Core.OsHle.Handles;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. namespace Ryujinx.Core.OsHle
  5. {
  6. class CondVar
  7. {
  8. private Process Process;
  9. private long CondVarAddress;
  10. private long Timeout;
  11. private bool OwnsCondVarValue;
  12. private List<KThread> WaitingThreads;
  13. public CondVar(Process Process, long CondVarAddress, long Timeout)
  14. {
  15. this.Process = Process;
  16. this.CondVarAddress = CondVarAddress;
  17. this.Timeout = Timeout;
  18. WaitingThreads = new List<KThread>();
  19. }
  20. public bool WaitForSignal(KThread Thread)
  21. {
  22. int Count = Process.Memory.ReadInt32(CondVarAddress);
  23. if (Count <= 0)
  24. {
  25. lock (WaitingThreads)
  26. {
  27. WaitingThreads.Add(Thread);
  28. }
  29. if (Timeout == -1)
  30. {
  31. Process.Scheduler.WaitForSignal(Thread);
  32. }
  33. else
  34. {
  35. bool Result = Process.Scheduler.WaitForSignal(Thread, (int)(Timeout / 1000000));
  36. lock (WaitingThreads)
  37. {
  38. WaitingThreads.Remove(Thread);
  39. }
  40. return Result;
  41. }
  42. }
  43. AcquireCondVarValue();
  44. Count = Process.Memory.ReadInt32(CondVarAddress);
  45. if (Count > 0)
  46. {
  47. Process.Memory.WriteInt32(CondVarAddress, Count - 1);
  48. }
  49. ReleaseCondVarValue();
  50. return true;
  51. }
  52. public void SetSignal(KThread Thread, int Count)
  53. {
  54. lock (WaitingThreads)
  55. {
  56. if (Count == -1)
  57. {
  58. Process.Scheduler.Signal(WaitingThreads.ToArray());
  59. AcquireCondVarValue();
  60. Process.Memory.WriteInt32(CondVarAddress, WaitingThreads.Count);
  61. ReleaseCondVarValue();
  62. WaitingThreads.Clear();
  63. }
  64. else
  65. {
  66. if (WaitingThreads.Count > 0)
  67. {
  68. int HighestPriority = WaitingThreads[0].Priority;
  69. int HighestPrioIndex = 0;
  70. for (int Index = 1; Index < WaitingThreads.Count; Index++)
  71. {
  72. if (HighestPriority > WaitingThreads[Index].Priority)
  73. {
  74. HighestPriority = WaitingThreads[Index].Priority;
  75. HighestPrioIndex = Index;
  76. }
  77. }
  78. Process.Scheduler.Signal(WaitingThreads[HighestPrioIndex]);
  79. WaitingThreads.RemoveAt(HighestPrioIndex);
  80. }
  81. AcquireCondVarValue();
  82. Process.Memory.WriteInt32(CondVarAddress, Count);
  83. ReleaseCondVarValue();
  84. }
  85. }
  86. Process.Scheduler.Suspend(Thread.ProcessorId);
  87. Process.Scheduler.Resume(Thread);
  88. }
  89. private void AcquireCondVarValue()
  90. {
  91. if (!OwnsCondVarValue)
  92. {
  93. while (!Process.Memory.AcquireAddress(CondVarAddress))
  94. {
  95. Thread.Yield();
  96. }
  97. OwnsCondVarValue = true;
  98. }
  99. }
  100. private void ReleaseCondVarValue()
  101. {
  102. if (OwnsCondVarValue)
  103. {
  104. OwnsCondVarValue = false;
  105. Process.Memory.ReleaseAddress(CondVarAddress);
  106. }
  107. }
  108. }
  109. }