diff options
| author | emmauss <emmausssss@gmail.com> | 2018-02-20 22:09:23 +0200 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-02-20 17:09:23 -0300 |
| commit | 62b827f474f0aa2152dd339fcc7cf31084e16a0b (patch) | |
| tree | 0e5c55b341aee4db0ccb841a084f253ec5e05657 /Ryujinx.Core/OsHle/CondVar.cs | |
| parent | cb665bb715834526d73c9469d16114b287faaecd (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.cs | 138 |
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 |
