AddressArbiter.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. using ChocolArm64.Memory;
  2. using ChocolArm64.State;
  3. using Ryujinx.HLE.OsHle.Handles;
  4. using static Ryujinx.HLE.OsHle.ErrorCode;
  5. namespace Ryujinx.HLE.OsHle.Kernel
  6. {
  7. static class AddressArbiter
  8. {
  9. static ulong WaitForAddress(Process Process, AThreadState ThreadState, long Address, ulong Timeout)
  10. {
  11. KThread CurrentThread = Process.GetThread(ThreadState.Tpidr);
  12. Process.Scheduler.SetReschedule(CurrentThread.ProcessorId);
  13. CurrentThread.ArbiterWaitAddress = Address;
  14. CurrentThread.ArbiterSignaled = false;
  15. Process.Scheduler.EnterWait(CurrentThread, NsTimeConverter.GetTimeMs(Timeout));
  16. if (!CurrentThread.ArbiterSignaled)
  17. {
  18. return MakeError(ErrorModule.Kernel, KernelErr.Timeout);
  19. }
  20. return 0;
  21. }
  22. public static ulong WaitForAddressIfLessThan(Process Process,
  23. AThreadState ThreadState,
  24. AMemory Memory,
  25. long Address,
  26. int Value,
  27. ulong Timeout,
  28. bool ShouldDecrement)
  29. {
  30. Memory.SetExclusive(ThreadState, Address);
  31. int CurrentValue = Memory.ReadInt32(Address);
  32. while (true)
  33. {
  34. if (Memory.TestExclusive(ThreadState, Address))
  35. {
  36. if (CurrentValue < Value)
  37. {
  38. if (ShouldDecrement)
  39. {
  40. Memory.WriteInt32(Address, CurrentValue - 1);
  41. }
  42. Memory.ClearExclusiveForStore(ThreadState);
  43. }
  44. else
  45. {
  46. Memory.ClearExclusiveForStore(ThreadState);
  47. return MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
  48. }
  49. break;
  50. }
  51. Memory.SetExclusive(ThreadState, Address);
  52. CurrentValue = Memory.ReadInt32(Address);
  53. }
  54. if (Timeout == 0)
  55. {
  56. return MakeError(ErrorModule.Kernel, KernelErr.Timeout);
  57. }
  58. return WaitForAddress(Process, ThreadState, Address, Timeout);
  59. }
  60. public static ulong WaitForAddressIfEqual(Process Process,
  61. AThreadState ThreadState,
  62. AMemory Memory,
  63. long Address,
  64. int Value,
  65. ulong Timeout)
  66. {
  67. if (Memory.ReadInt32(Address) != Value)
  68. {
  69. return MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
  70. }
  71. if (Timeout == 0)
  72. {
  73. return MakeError(ErrorModule.Kernel, KernelErr.Timeout);
  74. }
  75. return WaitForAddress(Process, ThreadState, Address, Timeout);
  76. }
  77. }
  78. enum ArbitrationType : int
  79. {
  80. WaitIfLessThan,
  81. DecrementAndWaitIfLessThan,
  82. WaitIfEqual
  83. }
  84. enum SignalType : int
  85. {
  86. Signal,
  87. IncrementAndSignalIfEqual,
  88. ModifyByWaitingCountAndSignalIfEqual
  89. }
  90. }