aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/OsHle/CondVar.cs
diff options
context:
space:
mode:
authoremmauss <emmausssss@gmail.com>2018-02-20 22:09:23 +0200
committergdkchan <gab.dark.100@gmail.com>2018-02-20 17:09:23 -0300
commit62b827f474f0aa2152dd339fcc7cf31084e16a0b (patch)
tree0e5c55b341aee4db0ccb841a084f253ec5e05657 /Ryujinx.Core/OsHle/CondVar.cs
parentcb665bb715834526d73c9469d16114b287faaecd (diff)
Split main project into core,graphics and chocolarm4 subproject (#29)
Diffstat (limited to 'Ryujinx.Core/OsHle/CondVar.cs')
-rw-r--r--Ryujinx.Core/OsHle/CondVar.cs138
1 files changed, 138 insertions, 0 deletions
diff --git a/Ryujinx.Core/OsHle/CondVar.cs b/Ryujinx.Core/OsHle/CondVar.cs
new file mode 100644
index 00000000..7b3e1852
--- /dev/null
+++ b/Ryujinx.Core/OsHle/CondVar.cs
@@ -0,0 +1,138 @@
+using Ryujinx.Core.OsHle.Handles;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Ryujinx.Core.OsHle
+{
+ public class CondVar
+ {
+ private Process Process;
+
+ private long CondVarAddress;
+ private long Timeout;
+
+ private bool OwnsCondVarValue;
+
+ private List<HThread> WaitingThreads;
+
+ public CondVar(Process Process, long CondVarAddress, long Timeout)
+ {
+ this.Process = Process;
+ this.CondVarAddress = CondVarAddress;
+ this.Timeout = Timeout;
+
+ WaitingThreads = new List<HThread>();
+ }
+
+ public void WaitForSignal(HThread Thread)
+ {
+ int Count = Process.Memory.ReadInt32(CondVarAddress);
+
+ if (Count <= 0)
+ {
+ lock (WaitingThreads)
+ {
+ WaitingThreads.Add(Thread);
+ }
+
+ if (Timeout == -1)
+ {
+ Process.Scheduler.WaitForSignal(Thread);
+ }
+ else
+ {
+ Process.Scheduler.WaitForSignal(Thread, (int)(Timeout / 1000000));
+
+ lock (WaitingThreads)
+ {
+ WaitingThreads.Remove(Thread);
+ }
+ }
+ }
+
+ AcquireCondVarValue();
+
+ Count = Process.Memory.ReadInt32(CondVarAddress);
+
+ if (Count > 0)
+ {
+ Process.Memory.WriteInt32(CondVarAddress, Count - 1);
+ }
+
+ ReleaseCondVarValue();
+ }
+
+ public void SetSignal(HThread Thread, int Count)
+ {
+ lock (WaitingThreads)
+ {
+ if (Count == -1)
+ {
+ Process.Scheduler.Signal(WaitingThreads.ToArray());
+
+ AcquireCondVarValue();
+
+ Process.Memory.WriteInt32(CondVarAddress, WaitingThreads.Count);
+
+ ReleaseCondVarValue();
+
+ WaitingThreads.Clear();
+ }
+ else
+ {
+ if (WaitingThreads.Count > 0)
+ {
+ int HighestPriority = WaitingThreads[0].Priority;
+ int HighestPrioIndex = 0;
+
+ for (int Index = 1; Index < WaitingThreads.Count; Index++)
+ {
+ if (HighestPriority > WaitingThreads[Index].Priority)
+ {
+ HighestPriority = WaitingThreads[Index].Priority;
+
+ HighestPrioIndex = Index;
+ }
+ }
+
+ Process.Scheduler.Signal(WaitingThreads[HighestPrioIndex]);
+
+ WaitingThreads.RemoveAt(HighestPrioIndex);
+ }
+
+ AcquireCondVarValue();
+
+ Process.Memory.WriteInt32(CondVarAddress, Count);
+
+ ReleaseCondVarValue();
+ }
+ }
+
+ Process.Scheduler.Suspend(Thread.ProcessorId);
+ Process.Scheduler.Resume(Thread);
+ }
+
+ private void AcquireCondVarValue()
+ {
+ if (!OwnsCondVarValue)
+ {
+ while (!Process.Memory.AcquireAddress(CondVarAddress))
+ {
+ Thread.Yield();
+ }
+
+ OwnsCondVarValue = true;
+ }
+ }
+
+ private void ReleaseCondVarValue()
+ {
+ if (OwnsCondVarValue)
+ {
+ OwnsCondVarValue = false;
+
+ Process.Memory.ReleaseAddress(CondVarAddress);
+ }
+ }
+ }
+} \ No newline at end of file