Mutex.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. using Ryujinx.Core.OsHle.Handles;
  2. using System.Collections.Concurrent;
  3. using System.Threading;
  4. namespace Ryujinx.Core.OsHle
  5. {
  6. public class Mutex
  7. {
  8. private const int MutexHasListenersMask = 0x40000000;
  9. private Process Process;
  10. private long MutexAddress;
  11. private bool OwnsMutexValue;
  12. private object EnterWaitLock;
  13. private ConcurrentQueue<HThread> WaitingThreads;
  14. public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle)
  15. {
  16. this.Process = Process;
  17. this.MutexAddress = MutexAddress;
  18. //Process.Memory.WriteInt32(MutexAddress, OwnerThreadHandle);
  19. EnterWaitLock = new object();
  20. WaitingThreads = new ConcurrentQueue<HThread>();
  21. }
  22. public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle)
  23. {
  24. AcquireMutexValue();
  25. lock (EnterWaitLock)
  26. {
  27. int CurrentThreadHandle = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask;
  28. if (CurrentThreadHandle == RequestingThreadHandle ||
  29. CurrentThreadHandle == 0)
  30. {
  31. return;
  32. }
  33. Process.Memory.WriteInt32(MutexAddress, CurrentThreadHandle | MutexHasListenersMask);
  34. ReleaseMutexValue();
  35. WaitingThreads.Enqueue(RequestingThread);
  36. }
  37. Process.Scheduler.WaitForSignal(RequestingThread);
  38. }
  39. public void GiveUpLock(int ThreadHandle)
  40. {
  41. AcquireMutexValue();
  42. lock (EnterWaitLock)
  43. {
  44. int CurrentThread = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask;
  45. if (CurrentThread == ThreadHandle)
  46. {
  47. Unlock();
  48. }
  49. }
  50. ReleaseMutexValue();
  51. }
  52. public void Unlock()
  53. {
  54. AcquireMutexValue();
  55. lock (EnterWaitLock)
  56. {
  57. int HasListeners = WaitingThreads.Count > 1 ? MutexHasListenersMask : 0;
  58. Process.Memory.WriteInt32(MutexAddress, HasListeners);
  59. ReleaseMutexValue();
  60. HThread[] UnlockedThreads = new HThread[WaitingThreads.Count];
  61. int Index = 0;
  62. while (WaitingThreads.TryDequeue(out HThread Thread))
  63. {
  64. UnlockedThreads[Index++] = Thread;
  65. }
  66. Process.Scheduler.Signal(UnlockedThreads);
  67. }
  68. }
  69. private void AcquireMutexValue()
  70. {
  71. if (!OwnsMutexValue)
  72. {
  73. while (!Process.Memory.AcquireAddress(MutexAddress))
  74. {
  75. Thread.Yield();
  76. }
  77. OwnsMutexValue = true;
  78. }
  79. }
  80. private void ReleaseMutexValue()
  81. {
  82. if (OwnsMutexValue)
  83. {
  84. OwnsMutexValue = false;
  85. Process.Memory.ReleaseAddress(MutexAddress);
  86. }
  87. }
  88. }
  89. }