AddressArbiter.cs 3.6 KB

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