ryujinx/Ryujinx.Core/OsHle/CondVar.cs

142 lines
3.8 KiB
C#
Raw Normal View History

using Ryujinx.Core.OsHle.Handles;
using System.Collections.Generic;
2018-02-19 19:37:13 +00:00
using System.Threading;
2018-02-04 23:08:20 +00:00
namespace Ryujinx.Core.OsHle
2018-02-04 23:08:20 +00:00
{
public class CondVar
2018-02-04 23:08:20 +00:00
{
private Process Process;
2018-02-04 23:08:20 +00:00
private long CondVarAddress;
private long Timeout;
2018-02-19 19:37:13 +00:00
private bool OwnsCondVarValue;
private List<HThread> WaitingThreads;
2018-02-04 23:08:20 +00:00
public CondVar(Process Process, long CondVarAddress, long Timeout)
2018-02-04 23:08:20 +00:00
{
this.Process = Process;
2018-02-04 23:08:20 +00:00
this.CondVarAddress = CondVarAddress;
this.Timeout = Timeout;
WaitingThreads = new List<HThread>();
2018-02-04 23:08:20 +00:00
}
public bool WaitForSignal(HThread Thread)
2018-02-04 23:08:20 +00:00
{
2018-02-19 19:37:13 +00:00
int Count = Process.Memory.ReadInt32(CondVarAddress);
2018-02-04 23:08:20 +00:00
if (Count <= 0)
{
2018-02-19 19:37:13 +00:00
lock (WaitingThreads)
{
WaitingThreads.Add(Thread);
}
if (Timeout == -1)
{
Process.Scheduler.WaitForSignal(Thread);
}
else
{
bool Result = Process.Scheduler.WaitForSignal(Thread, (int)(Timeout / 1000000));
2018-02-19 19:37:13 +00:00
lock (WaitingThreads)
{
WaitingThreads.Remove(Thread);
}
return Result;
2018-02-19 19:37:13 +00:00
}
2018-02-04 23:08:20 +00:00
}
2018-02-19 19:37:13 +00:00
AcquireCondVarValue();
2018-02-04 23:08:20 +00:00
2018-02-19 19:37:13 +00:00
Count = Process.Memory.ReadInt32(CondVarAddress);
2018-02-04 23:08:20 +00:00
2018-02-19 19:37:13 +00:00
if (Count > 0)
2018-02-04 23:08:20 +00:00
{
2018-02-19 19:37:13 +00:00
Process.Memory.WriteInt32(CondVarAddress, Count - 1);
2018-02-04 23:08:20 +00:00
}
2018-02-19 19:37:13 +00:00
ReleaseCondVarValue();
return true;
2018-02-04 23:08:20 +00:00
}
2018-02-19 19:37:13 +00:00
public void SetSignal(HThread Thread, int Count)
2018-02-04 23:08:20 +00:00
{
lock (WaitingThreads)
2018-02-04 23:08:20 +00:00
{
if (Count == -1)
2018-02-04 23:08:20 +00:00
{
Process.Scheduler.Signal(WaitingThreads.ToArray());
2018-02-04 23:08:20 +00:00
2018-02-19 19:37:13 +00:00
AcquireCondVarValue();
Process.Memory.WriteInt32(CondVarAddress, WaitingThreads.Count);
ReleaseCondVarValue();
WaitingThreads.Clear();
2018-02-04 23:08:20 +00:00
}
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);
}
2018-02-04 23:08:20 +00:00
2018-02-19 19:37:13 +00:00
AcquireCondVarValue();
Process.Memory.WriteInt32(CondVarAddress, Count);
ReleaseCondVarValue();
}
2018-02-04 23:08:20 +00:00
}
2018-02-19 19:37:13 +00:00
Process.Scheduler.Suspend(Thread.ProcessorId);
Process.Scheduler.Resume(Thread);
2018-02-04 23:08:20 +00:00
}
2018-02-19 19:37:13 +00:00
private void AcquireCondVarValue()
{
2018-02-19 19:37:13 +00:00
if (!OwnsCondVarValue)
{
while (!Process.Memory.AcquireAddress(CondVarAddress))
{
Thread.Yield();
}
OwnsCondVarValue = true;
}
}
2018-02-19 19:37:13 +00:00
private void ReleaseCondVarValue()
{
2018-02-19 19:37:13 +00:00
if (OwnsCondVarValue)
{
OwnsCondVarValue = false;
Process.Memory.ReleaseAddress(CondVarAddress);
}
}
2018-02-04 23:08:20 +00:00
}
}