CondVar.cs 3.7 KB

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