aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs111
1 files changed, 111 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs b/Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs
new file mode 100644
index 00000000..d7df0a72
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs
@@ -0,0 +1,111 @@
+using ChocolArm64.Memory;
+using ChocolArm64.State;
+
+using static Ryujinx.HLE.HOS.ErrorCode;
+
+namespace Ryujinx.HLE.HOS.Kernel
+{
+ static class AddressArbiter
+ {
+ static ulong WaitForAddress(Process Process, AThreadState ThreadState, long Address, ulong Timeout)
+ {
+ KThread CurrentThread = Process.GetThread(ThreadState.Tpidr);
+
+ Process.Scheduler.SetReschedule(CurrentThread.ProcessorId);
+
+ CurrentThread.ArbiterWaitAddress = Address;
+ CurrentThread.ArbiterSignaled = false;
+
+ Process.Scheduler.EnterWait(CurrentThread, NsTimeConverter.GetTimeMs(Timeout));
+
+ if (!CurrentThread.ArbiterSignaled)
+ {
+ return MakeError(ErrorModule.Kernel, KernelErr.Timeout);
+ }
+
+ return 0;
+ }
+
+ public static ulong WaitForAddressIfLessThan(Process Process,
+ AThreadState ThreadState,
+ AMemory Memory,
+ long Address,
+ int Value,
+ ulong Timeout,
+ bool ShouldDecrement)
+ {
+ Memory.SetExclusive(ThreadState, Address);
+
+ int CurrentValue = Memory.ReadInt32(Address);
+
+ while (true)
+ {
+ if (Memory.TestExclusive(ThreadState, Address))
+ {
+ if (CurrentValue < Value)
+ {
+ if (ShouldDecrement)
+ {
+ Memory.WriteInt32(Address, CurrentValue - 1);
+ }
+
+ Memory.ClearExclusiveForStore(ThreadState);
+ }
+ else
+ {
+ Memory.ClearExclusiveForStore(ThreadState);
+
+ return MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
+ }
+
+ break;
+ }
+
+ Memory.SetExclusive(ThreadState, Address);
+
+ CurrentValue = Memory.ReadInt32(Address);
+ }
+
+ if (Timeout == 0)
+ {
+ return MakeError(ErrorModule.Kernel, KernelErr.Timeout);
+ }
+
+ return WaitForAddress(Process, ThreadState, Address, Timeout);
+ }
+
+ public static ulong WaitForAddressIfEqual(Process Process,
+ AThreadState ThreadState,
+ AMemory Memory,
+ long Address,
+ int Value,
+ ulong Timeout)
+ {
+ if (Memory.ReadInt32(Address) != Value)
+ {
+ return MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
+ }
+
+ if (Timeout == 0)
+ {
+ return MakeError(ErrorModule.Kernel, KernelErr.Timeout);
+ }
+
+ return WaitForAddress(Process, ThreadState, Address, Timeout);
+ }
+ }
+
+ enum ArbitrationType : int
+ {
+ WaitIfLessThan,
+ DecrementAndWaitIfLessThan,
+ WaitIfEqual
+ }
+
+ enum SignalType : int
+ {
+ Signal,
+ IncrementAndSignalIfEqual,
+ ModifyByWaitingCountAndSignalIfEqual
+ }
+}