Mutex.cs 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. using ChocolArm64.Memory;
  2. using Ryujinx.OsHle.Handles;
  3. using System.Collections.Concurrent;
  4. namespace Ryujinx.OsHle
  5. {
  6. class Mutex
  7. {
  8. private const int MutexHasListenersMask = 0x40000000;
  9. private Process Process;
  10. private long MutexAddress;
  11. private object EnterWaitLock;
  12. private ConcurrentQueue<HThread> WaitingThreads;
  13. public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle)
  14. {
  15. this.Process = Process;
  16. this.MutexAddress = MutexAddress;
  17. //Process.Memory.WriteInt32(MutexAddress, OwnerThreadHandle);
  18. EnterWaitLock = new object();
  19. WaitingThreads = new ConcurrentQueue<HThread>();
  20. }
  21. public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle)
  22. {
  23. lock (EnterWaitLock)
  24. {
  25. int CurrentThreadHandle = ReadMutexValue() & ~MutexHasListenersMask;
  26. if (CurrentThreadHandle == RequestingThreadHandle ||
  27. CurrentThreadHandle == 0)
  28. {
  29. return;
  30. }
  31. WriteMutexValue(CurrentThreadHandle | MutexHasListenersMask);
  32. WaitingThreads.Enqueue(RequestingThread);
  33. }
  34. Process.Scheduler.WaitForSignal(RequestingThread);
  35. }
  36. public void GiveUpLock(int ThreadHandle)
  37. {
  38. lock (EnterWaitLock)
  39. {
  40. int CurrentThread = ReadMutexValue() & ~MutexHasListenersMask;
  41. if (CurrentThread == ThreadHandle)
  42. {
  43. Unlock();
  44. }
  45. }
  46. }
  47. public void Unlock()
  48. {
  49. lock (EnterWaitLock)
  50. {
  51. int HasListeners = WaitingThreads.Count > 1 ? MutexHasListenersMask : 0;
  52. WriteMutexValue(HasListeners);
  53. HThread[] UnlockedThreads = new HThread[WaitingThreads.Count];
  54. int Index = 0;
  55. while (WaitingThreads.TryDequeue(out HThread Thread))
  56. {
  57. UnlockedThreads[Index++] = Thread;
  58. }
  59. Process.Scheduler.Signal(UnlockedThreads);
  60. }
  61. }
  62. private int ReadMutexValue()
  63. {
  64. return AMemoryHelper.ReadInt32Exclusive(Process.Memory, MutexAddress);
  65. }
  66. private void WriteMutexValue(int Value)
  67. {
  68. AMemoryHelper.WriteInt32Exclusive(Process.Memory, MutexAddress, Value);
  69. }
  70. }
  71. }