Revert "Started to work in improving the sync primitives"
This commit is contained in:
parent
a5bc98be03
commit
ae55f1b9d4
9 changed files with 364 additions and 475 deletions
|
@ -13,23 +13,17 @@ namespace Ryujinx.Core.OsHle.Handles
|
||||||
{
|
{
|
||||||
public KThread Thread { get; private set; }
|
public KThread Thread { get; private set; }
|
||||||
|
|
||||||
public ManualResetEvent SyncWaitEvent { get; private set; }
|
public AutoResetEvent WaitEvent { get; private set; }
|
||||||
public AutoResetEvent SchedWaitEvent { get; private set; }
|
|
||||||
|
|
||||||
public bool Active { get; set; }
|
public bool Active { get; set; }
|
||||||
|
|
||||||
public int SyncTimeout { get; set; }
|
|
||||||
|
|
||||||
public SchedulerThread(KThread Thread)
|
public SchedulerThread(KThread Thread)
|
||||||
{
|
{
|
||||||
this.Thread = Thread;
|
this.Thread = Thread;
|
||||||
|
|
||||||
SyncWaitEvent = new ManualResetEvent(true);
|
WaitEvent = new AutoResetEvent(false);
|
||||||
SchedWaitEvent = new AutoResetEvent(false);
|
|
||||||
|
|
||||||
Active = true;
|
Active = true;
|
||||||
|
|
||||||
SyncTimeout = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -41,8 +35,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
||||||
{
|
{
|
||||||
if (Disposing)
|
if (Disposing)
|
||||||
{
|
{
|
||||||
SyncWaitEvent.Dispose();
|
WaitEvent.Dispose();
|
||||||
SchedWaitEvent.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,66 +194,45 @@ namespace Ryujinx.Core.OsHle.Handles
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
SchedThread.Active = Active;
|
lock (SchedLock)
|
||||||
|
|
||||||
UpdateSyncWaitEvent(SchedThread);
|
|
||||||
|
|
||||||
WaitIfNeeded(SchedThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EnterWait(KThread Thread, int Timeout = -1)
|
|
||||||
{
|
|
||||||
if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
bool OldState = SchedThread.Active;
|
||||||
|
|
||||||
|
SchedThread.Active = Active;
|
||||||
|
|
||||||
|
if (!OldState && Active)
|
||||||
|
{
|
||||||
|
if (ActiveProcessors.Add(Thread.ProcessorId))
|
||||||
|
{
|
||||||
|
RunThread(SchedThread);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WaitingToRun[Thread.ProcessorId].Push(SchedThread);
|
||||||
|
|
||||||
|
PrintDbgThreadInfo(Thread, "entering wait state...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (OldState && !Active)
|
||||||
|
{
|
||||||
|
if (Thread.Thread.IsCurrentThread())
|
||||||
|
{
|
||||||
|
Suspend(Thread.ProcessorId);
|
||||||
|
|
||||||
|
PrintDbgThreadInfo(Thread, "entering inactive wait state...");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WaitingToRun[Thread.ProcessorId].Remove(SchedThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SchedThread.SyncTimeout = Timeout;
|
if (!Active && Thread.Thread.IsCurrentThread())
|
||||||
|
|
||||||
UpdateSyncWaitEvent(SchedThread);
|
|
||||||
|
|
||||||
return WaitIfNeeded(SchedThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WakeUp(KThread Thread)
|
|
||||||
{
|
|
||||||
if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
SchedThread.WaitEvent.WaitOne();
|
||||||
}
|
|
||||||
|
|
||||||
SchedThread.SyncTimeout = 0;
|
PrintDbgThreadInfo(Thread, "resuming execution...");
|
||||||
|
|
||||||
UpdateSyncWaitEvent(SchedThread);
|
|
||||||
|
|
||||||
WaitIfNeeded(SchedThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateSyncWaitEvent(SchedulerThread SchedThread)
|
|
||||||
{
|
|
||||||
if (SchedThread.Active && SchedThread.SyncTimeout == 0)
|
|
||||||
{
|
|
||||||
SchedThread.SyncWaitEvent.Set();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SchedThread.SyncWaitEvent.Reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool WaitIfNeeded(SchedulerThread SchedThread)
|
|
||||||
{
|
|
||||||
KThread Thread = SchedThread.Thread;
|
|
||||||
|
|
||||||
if (!IsActive(SchedThread) && Thread.Thread.IsCurrentThread())
|
|
||||||
{
|
|
||||||
Suspend(Thread.ProcessorId);
|
|
||||||
|
|
||||||
return Resume(Thread);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,76 +263,64 @@ namespace Ryujinx.Core.OsHle.Handles
|
||||||
{
|
{
|
||||||
SchedulerThread SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.Priority);
|
SchedulerThread SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.Priority);
|
||||||
|
|
||||||
if (IsActive(Thread) && SchedThread == null)
|
if (SchedThread == null)
|
||||||
{
|
{
|
||||||
PrintDbgThreadInfo(Thread, "resumed because theres nothing better to run.");
|
PrintDbgThreadInfo(Thread, "resumed because theres nothing better to run.");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SchedThread != null)
|
RunThread(SchedThread);
|
||||||
{
|
|
||||||
RunThread(SchedThread);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Resume(Thread);
|
Resume(Thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Resume(KThread Thread)
|
public void Resume(KThread Thread)
|
||||||
{
|
{
|
||||||
if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
|
if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return TryResumingExecution(SchedThread);
|
TryResumingExecution(SchedThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryResumingExecution(SchedulerThread SchedThread)
|
private void TryResumingExecution(SchedulerThread SchedThread)
|
||||||
{
|
{
|
||||||
KThread Thread = SchedThread.Thread;
|
KThread Thread = SchedThread.Thread;
|
||||||
|
|
||||||
if (!SchedThread.Active || SchedThread.SyncTimeout != 0)
|
if (SchedThread.Active)
|
||||||
|
{
|
||||||
|
lock (SchedLock)
|
||||||
|
{
|
||||||
|
if (ActiveProcessors.Add(Thread.ProcessorId))
|
||||||
|
{
|
||||||
|
PrintDbgThreadInfo(Thread, "resuming execution...");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitingToRun[Thread.ProcessorId].Push(SchedThread);
|
||||||
|
|
||||||
|
PrintDbgThreadInfo(Thread, "entering wait state...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
PrintDbgThreadInfo(Thread, "entering inactive wait state...");
|
PrintDbgThreadInfo(Thread, "entering inactive wait state...");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Result = false;
|
SchedThread.WaitEvent.WaitOne();
|
||||||
|
|
||||||
if (SchedThread.SyncTimeout != 0)
|
|
||||||
{
|
|
||||||
Result = SchedThread.SyncWaitEvent.WaitOne(SchedThread.SyncTimeout);
|
|
||||||
|
|
||||||
SchedThread.SyncTimeout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (SchedLock)
|
|
||||||
{
|
|
||||||
if (ActiveProcessors.Add(Thread.ProcessorId))
|
|
||||||
{
|
|
||||||
PrintDbgThreadInfo(Thread, "resuming execution...");
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
WaitingToRun[Thread.ProcessorId].Push(SchedThread);
|
|
||||||
|
|
||||||
PrintDbgThreadInfo(Thread, "entering wait state...");
|
|
||||||
}
|
|
||||||
|
|
||||||
SchedThread.SchedWaitEvent.WaitOne();
|
|
||||||
|
|
||||||
PrintDbgThreadInfo(Thread, "resuming execution...");
|
PrintDbgThreadInfo(Thread, "resuming execution...");
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunThread(SchedulerThread SchedThread)
|
private void RunThread(SchedulerThread SchedThread)
|
||||||
{
|
{
|
||||||
if (!SchedThread.Thread.Thread.Execute())
|
if (!SchedThread.Thread.Thread.Execute())
|
||||||
{
|
{
|
||||||
SchedThread.SchedWaitEvent.Set();
|
SchedThread.WaitEvent.Set();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -368,21 +328,6 @@ namespace Ryujinx.Core.OsHle.Handles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsActive(KThread Thread)
|
|
||||||
{
|
|
||||||
if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return IsActive(SchedThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsActive(SchedulerThread SchedThread)
|
|
||||||
{
|
|
||||||
return SchedThread.Active && SchedThread.SyncTimeout == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PrintDbgThreadInfo(KThread Thread, string Message)
|
private void PrintDbgThreadInfo(KThread Thread, string Message)
|
||||||
{
|
{
|
||||||
Logging.Debug(LogClass.KernelScheduler, "(" +
|
Logging.Debug(LogClass.KernelScheduler, "(" +
|
||||||
|
|
|
@ -6,19 +6,10 @@ namespace Ryujinx.Core.OsHle.Handles
|
||||||
{
|
{
|
||||||
public AThread Thread { get; private set; }
|
public AThread Thread { get; private set; }
|
||||||
|
|
||||||
public KThread NextMutexThread { get; set; }
|
|
||||||
public KThread NextCondVarThread { get; set; }
|
|
||||||
|
|
||||||
public long MutexAddress { get; set; }
|
|
||||||
public long CondVarAddress { get; set; }
|
|
||||||
|
|
||||||
public int ProcessorId { get; private set; }
|
public int ProcessorId { get; private set; }
|
||||||
|
|
||||||
public int Priority { get; private set; }
|
public int Priority { get; set; }
|
||||||
|
public int Handle { get; set; }
|
||||||
private int DesiredPriority;
|
|
||||||
|
|
||||||
public int Handle { get; set; }
|
|
||||||
|
|
||||||
public int ThreadId => Thread.ThreadId;
|
public int ThreadId => Thread.ThreadId;
|
||||||
|
|
||||||
|
@ -26,28 +17,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
||||||
{
|
{
|
||||||
this.Thread = Thread;
|
this.Thread = Thread;
|
||||||
this.ProcessorId = ProcessorId;
|
this.ProcessorId = ProcessorId;
|
||||||
|
this.Priority = Priority;
|
||||||
SetPriority(Priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPriority(int Priority)
|
|
||||||
{
|
|
||||||
this.Priority = DesiredPriority = Priority;
|
|
||||||
|
|
||||||
UpdatePriority();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetPriority()
|
|
||||||
{
|
|
||||||
Priority = DesiredPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdatePriority()
|
|
||||||
{
|
|
||||||
if (Priority > (NextMutexThread?.Priority ?? Priority))
|
|
||||||
{
|
|
||||||
Priority = NextMutexThread.Priority;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
148
Ryujinx.Core/OsHle/Kernel/ConditionVariable.cs
Normal file
148
Ryujinx.Core/OsHle/Kernel/ConditionVariable.cs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
using Ryujinx.Core.OsHle.Handles;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.OsHle.Kernel
|
||||||
|
{
|
||||||
|
class ConditionVariable
|
||||||
|
{
|
||||||
|
private Process Process;
|
||||||
|
|
||||||
|
private long CondVarAddress;
|
||||||
|
|
||||||
|
private bool OwnsCondVarValue;
|
||||||
|
|
||||||
|
private List<(KThread Thread, AutoResetEvent WaitEvent)> WaitingThreads;
|
||||||
|
|
||||||
|
public ConditionVariable(Process Process, long CondVarAddress)
|
||||||
|
{
|
||||||
|
this.Process = Process;
|
||||||
|
this.CondVarAddress = CondVarAddress;
|
||||||
|
|
||||||
|
WaitingThreads = new List<(KThread, AutoResetEvent)>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool WaitForSignal(KThread Thread, ulong Timeout)
|
||||||
|
{
|
||||||
|
bool Result = true;
|
||||||
|
|
||||||
|
int Count = Process.Memory.ReadInt32(CondVarAddress);
|
||||||
|
|
||||||
|
if (Count <= 0)
|
||||||
|
{
|
||||||
|
using (AutoResetEvent WaitEvent = new AutoResetEvent(false))
|
||||||
|
{
|
||||||
|
lock (WaitingThreads)
|
||||||
|
{
|
||||||
|
WaitingThreads.Add((Thread, WaitEvent));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Timeout == ulong.MaxValue)
|
||||||
|
{
|
||||||
|
Result = WaitEvent.WaitOne();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result = WaitEvent.WaitOne(NsTimeConverter.GetTimeMs(Timeout));
|
||||||
|
|
||||||
|
lock (WaitingThreads)
|
||||||
|
{
|
||||||
|
WaitingThreads.Remove((Thread, WaitEvent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AcquireCondVarValue();
|
||||||
|
|
||||||
|
Count = Process.Memory.ReadInt32(CondVarAddress);
|
||||||
|
|
||||||
|
if (Result && Count > 0)
|
||||||
|
{
|
||||||
|
Process.Memory.WriteInt32(CondVarAddress, Count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseCondVarValue();
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSignal(KThread Thread, int Count)
|
||||||
|
{
|
||||||
|
lock (WaitingThreads)
|
||||||
|
{
|
||||||
|
if (Count < 0)
|
||||||
|
{
|
||||||
|
foreach ((_, AutoResetEvent WaitEvent) in WaitingThreads)
|
||||||
|
{
|
||||||
|
IncrementCondVarValue();
|
||||||
|
|
||||||
|
WaitEvent.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitingThreads.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (WaitingThreads.Count > 0 && Count-- > 0)
|
||||||
|
{
|
||||||
|
int HighestPriority = WaitingThreads[0].Thread.Priority;
|
||||||
|
int HighestPrioIndex = 0;
|
||||||
|
|
||||||
|
for (int Index = 1; Index < WaitingThreads.Count; Index++)
|
||||||
|
{
|
||||||
|
if (HighestPriority > WaitingThreads[Index].Thread.Priority)
|
||||||
|
{
|
||||||
|
HighestPriority = WaitingThreads[Index].Thread.Priority;
|
||||||
|
|
||||||
|
HighestPrioIndex = Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IncrementCondVarValue();
|
||||||
|
|
||||||
|
WaitingThreads[HighestPrioIndex].WaitEvent.Set();
|
||||||
|
|
||||||
|
WaitingThreads.RemoveAt(HighestPrioIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process.Scheduler.Yield(Thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void IncrementCondVarValue()
|
||||||
|
{
|
||||||
|
AcquireCondVarValue();
|
||||||
|
|
||||||
|
int Count = Process.Memory.ReadInt32(CondVarAddress);
|
||||||
|
|
||||||
|
Process.Memory.WriteInt32(CondVarAddress, Count + 1);
|
||||||
|
|
||||||
|
ReleaseCondVarValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,11 +2,9 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
{
|
{
|
||||||
static class KernelErr
|
static class KernelErr
|
||||||
{
|
{
|
||||||
public const int InvalidAlignment = 102;
|
public const int InvalidMemRange = 110;
|
||||||
public const int InvalidAddress = 106;
|
public const int InvalidHandle = 114;
|
||||||
public const int InvalidMemRange = 110;
|
public const int Timeout = 117;
|
||||||
public const int InvalidHandle = 114;
|
public const int InvalidInfo = 120;
|
||||||
public const int Timeout = 117;
|
|
||||||
public const int InvalidInfo = 120;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
95
Ryujinx.Core/OsHle/Kernel/MutualExclusion.cs
Normal file
95
Ryujinx.Core/OsHle/Kernel/MutualExclusion.cs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
using Ryujinx.Core.OsHle.Handles;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Ryujinx.Core.OsHle.Kernel
|
||||||
|
{
|
||||||
|
class MutualExclusion
|
||||||
|
{
|
||||||
|
private const int MutexHasListenersMask = 0x40000000;
|
||||||
|
|
||||||
|
private Process Process;
|
||||||
|
|
||||||
|
private long MutexAddress;
|
||||||
|
|
||||||
|
private int OwnerThreadHandle;
|
||||||
|
|
||||||
|
private List<(KThread Thread, AutoResetEvent WaitEvent)> WaitingThreads;
|
||||||
|
|
||||||
|
public MutualExclusion(Process Process, long MutexAddress)
|
||||||
|
{
|
||||||
|
this.Process = Process;
|
||||||
|
this.MutexAddress = MutexAddress;
|
||||||
|
|
||||||
|
WaitingThreads = new List<(KThread, AutoResetEvent)>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WaitForLock(KThread RequestingThread)
|
||||||
|
{
|
||||||
|
WaitForLock(RequestingThread, OwnerThreadHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WaitForLock(KThread RequestingThread, int OwnerThreadHandle)
|
||||||
|
{
|
||||||
|
if (OwnerThreadHandle == RequestingThread.Handle ||
|
||||||
|
OwnerThreadHandle == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (AutoResetEvent WaitEvent = new AutoResetEvent(false))
|
||||||
|
{
|
||||||
|
lock (WaitingThreads)
|
||||||
|
{
|
||||||
|
WaitingThreads.Add((RequestingThread, WaitEvent));
|
||||||
|
}
|
||||||
|
|
||||||
|
Process.Scheduler.Suspend(RequestingThread.ProcessorId);
|
||||||
|
|
||||||
|
WaitEvent.WaitOne();
|
||||||
|
|
||||||
|
Process.Scheduler.Resume(RequestingThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unlock()
|
||||||
|
{
|
||||||
|
lock (WaitingThreads)
|
||||||
|
{
|
||||||
|
int HasListeners = WaitingThreads.Count > 1 ? MutexHasListenersMask : 0;
|
||||||
|
|
||||||
|
if (WaitingThreads.Count > 0)
|
||||||
|
{
|
||||||
|
int HighestPriority = WaitingThreads[0].Thread.Priority;
|
||||||
|
int HighestPrioIndex = 0;
|
||||||
|
|
||||||
|
for (int Index = 1; Index < WaitingThreads.Count; Index++)
|
||||||
|
{
|
||||||
|
if (HighestPriority > WaitingThreads[Index].Thread.Priority)
|
||||||
|
{
|
||||||
|
HighestPriority = WaitingThreads[Index].Thread.Priority;
|
||||||
|
|
||||||
|
HighestPrioIndex = Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Handle = WaitingThreads[HighestPrioIndex].Thread.Handle;
|
||||||
|
|
||||||
|
WaitingThreads[HighestPrioIndex].WaitEvent.Set();
|
||||||
|
|
||||||
|
WaitingThreads.RemoveAt(HighestPrioIndex);
|
||||||
|
|
||||||
|
Process.Memory.WriteInt32(MutexAddress, HasListeners | Handle);
|
||||||
|
|
||||||
|
OwnerThreadHandle = Handle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Process.Memory.WriteInt32(MutexAddress, 0);
|
||||||
|
|
||||||
|
OwnerThreadHandle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ using ChocolArm64.Memory;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using Ryujinx.Core.OsHle.Handles;
|
using Ryujinx.Core.OsHle.Handles;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle.Kernel
|
namespace Ryujinx.Core.OsHle.Kernel
|
||||||
|
@ -17,6 +18,9 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
private Process Process;
|
private Process Process;
|
||||||
private AMemory Memory;
|
private AMemory Memory;
|
||||||
|
|
||||||
|
private ConcurrentDictionary<long, MutualExclusion> Mutexes;
|
||||||
|
private ConcurrentDictionary<long, ConditionVariable> CondVars;
|
||||||
|
|
||||||
private HashSet<(HSharedMem, long)> MappedSharedMems;
|
private HashSet<(HSharedMem, long)> MappedSharedMems;
|
||||||
|
|
||||||
private ulong CurrentHeapSize;
|
private ulong CurrentHeapSize;
|
||||||
|
@ -67,6 +71,9 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
this.Process = Process;
|
this.Process = Process;
|
||||||
this.Memory = Process.Memory;
|
this.Memory = Process.Memory;
|
||||||
|
|
||||||
|
Mutexes = new ConcurrentDictionary<long, MutualExclusion>();
|
||||||
|
CondVars = new ConcurrentDictionary<long, ConditionVariable>();
|
||||||
|
|
||||||
MappedSharedMems = new HashSet<(HSharedMem, long)>();
|
MappedSharedMems = new HashSet<(HSharedMem, long)>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
|
|
||||||
if (CurrThread != null)
|
if (CurrThread != null)
|
||||||
{
|
{
|
||||||
CurrThread.SetPriority(Priority);
|
CurrThread.Priority = Priority;
|
||||||
|
|
||||||
ThreadState.X0 = 0;
|
ThreadState.X0 = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using Ryujinx.Core.OsHle.Handles;
|
using Ryujinx.Core.OsHle.Handles;
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
using static Ryujinx.Core.OsHle.ErrorCode;
|
using static Ryujinx.Core.OsHle.ErrorCode;
|
||||||
|
|
||||||
|
@ -9,32 +7,12 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
{
|
{
|
||||||
partial class SvcHandler
|
partial class SvcHandler
|
||||||
{
|
{
|
||||||
private const int MutexHasListenersMask = 0x40000000;
|
|
||||||
|
|
||||||
private void SvcArbitrateLock(AThreadState ThreadState)
|
private void SvcArbitrateLock(AThreadState ThreadState)
|
||||||
{
|
{
|
||||||
int OwnerThreadHandle = (int)ThreadState.X0;
|
int OwnerThreadHandle = (int)ThreadState.X0;
|
||||||
long MutexAddress = (long)ThreadState.X1;
|
long MutexAddress = (long)ThreadState.X1;
|
||||||
int RequestingThreadHandle = (int)ThreadState.X2;
|
int RequestingThreadHandle = (int)ThreadState.X2;
|
||||||
|
|
||||||
if (IsPointingInsideKernel(MutexAddress))
|
|
||||||
{
|
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
|
||||||
|
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsWordAddressUnaligned(MutexAddress))
|
|
||||||
{
|
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
|
||||||
|
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAlignment);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
KThread OwnerThread = Process.HandleTable.GetData<KThread>(OwnerThreadHandle);
|
KThread OwnerThread = Process.HandleTable.GetData<KThread>(OwnerThreadHandle);
|
||||||
|
|
||||||
if (OwnerThread == null)
|
if (OwnerThread == null)
|
||||||
|
@ -57,7 +35,9 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MutexLock(MutexAddress, RequestingThread, OwnerThreadHandle);
|
MutualExclusion Mutex = GetMutex(MutexAddress);
|
||||||
|
|
||||||
|
Mutex.WaitForLock(RequestingThread, OwnerThreadHandle);
|
||||||
|
|
||||||
ThreadState.X0 = 0;
|
ThreadState.X0 = 0;
|
||||||
}
|
}
|
||||||
|
@ -66,28 +46,9 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
{
|
{
|
||||||
long MutexAddress = (long)ThreadState.X0;
|
long MutexAddress = (long)ThreadState.X0;
|
||||||
|
|
||||||
if (IsPointingInsideKernel(MutexAddress))
|
GetMutex(MutexAddress).Unlock();
|
||||||
{
|
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
|
||||||
|
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
Process.Scheduler.Yield(Process.GetThread(ThreadState.Tpidr));
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsWordAddressUnaligned(MutexAddress))
|
|
||||||
{
|
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
|
||||||
|
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAlignment);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MutexUnlock(Process.GetThread(ThreadState.Tpidr), MutexAddress))
|
|
||||||
{
|
|
||||||
Process.Scheduler.Yield(Process.GetThread(ThreadState.Tpidr));
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadState.X0 = 0;
|
ThreadState.X0 = 0;
|
||||||
}
|
}
|
||||||
|
@ -99,24 +60,6 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
int ThreadHandle = (int)ThreadState.X2;
|
int ThreadHandle = (int)ThreadState.X2;
|
||||||
ulong Timeout = ThreadState.X3;
|
ulong Timeout = ThreadState.X3;
|
||||||
|
|
||||||
if (IsPointingInsideKernel(MutexAddress))
|
|
||||||
{
|
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
|
||||||
|
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsWordAddressUnaligned(MutexAddress))
|
|
||||||
{
|
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
|
||||||
|
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAlignment);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
KThread Thread = Process.HandleTable.GetData<KThread>(ThreadHandle);
|
KThread Thread = Process.HandleTable.GetData<KThread>(ThreadHandle);
|
||||||
|
|
||||||
if (Thread == null)
|
if (Thread == null)
|
||||||
|
@ -124,20 +67,24 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
|
Logging.Warn(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
|
||||||
|
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MutexUnlock(Process.GetThread(ThreadState.Tpidr), MutexAddress);
|
Process.Scheduler.Suspend(Thread.ProcessorId);
|
||||||
|
|
||||||
if (!CondVarWait(Thread, MutexAddress, CondVarAddress, Timeout))
|
MutualExclusion Mutex = GetMutex(MutexAddress);
|
||||||
|
|
||||||
|
Mutex.Unlock();
|
||||||
|
|
||||||
|
if (!GetCondVar(CondVarAddress).WaitForSignal(Thread, Timeout))
|
||||||
{
|
{
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Process.Scheduler.Yield(Process.GetThread(ThreadState.Tpidr));
|
Mutex.WaitForLock(Thread);
|
||||||
|
|
||||||
|
Process.Scheduler.Resume(Thread);
|
||||||
|
|
||||||
ThreadState.X0 = 0;
|
ThreadState.X0 = 0;
|
||||||
}
|
}
|
||||||
|
@ -147,227 +94,31 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
long CondVarAddress = (long)ThreadState.X0;
|
long CondVarAddress = (long)ThreadState.X0;
|
||||||
int Count = (int)ThreadState.X1;
|
int Count = (int)ThreadState.X1;
|
||||||
|
|
||||||
CondVarSignal(CondVarAddress, Count);
|
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
|
||||||
|
|
||||||
|
GetCondVar(CondVarAddress).SetSignal(CurrThread, Count);
|
||||||
|
|
||||||
ThreadState.X0 = 0;
|
ThreadState.X0 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MutexLock(long MutexAddress, KThread RequestingThread, int OwnerThreadHandle)
|
private MutualExclusion GetMutex(long MutexAddress)
|
||||||
{
|
{
|
||||||
int MutexValue = Process.Memory.ReadInt32(MutexAddress);
|
MutualExclusion MutexFactory(long Key)
|
||||||
|
|
||||||
if (MutexValue != (OwnerThreadHandle | MutexHasListenersMask))
|
|
||||||
{
|
{
|
||||||
return;
|
return new MutualExclusion(Process, MutexAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertWaitingMutexThread(OwnerThreadHandle, RequestingThread);
|
return Mutexes.GetOrAdd(MutexAddress, MutexFactory);
|
||||||
|
|
||||||
RequestingThread.MutexAddress = MutexAddress;
|
|
||||||
|
|
||||||
Process.Scheduler.EnterWait(RequestingThread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool MutexUnlock(KThread CurrThread, long MutexAddress)
|
private ConditionVariable GetCondVar(long CondVarAddress)
|
||||||
{
|
{
|
||||||
if (CurrThread == null)
|
ConditionVariable CondVarFactory(long Key)
|
||||||
{
|
{
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Invalid mutex 0x{MutexAddress:x16}!");
|
return new ConditionVariable(Process, CondVarAddress);
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrThread.MutexAddress = 0;
|
return CondVars.GetOrAdd(CondVarAddress, CondVarFactory);
|
||||||
CurrThread.CondVarAddress = 0;
|
|
||||||
|
|
||||||
CurrThread.ResetPriority();
|
|
||||||
|
|
||||||
KThread OwnerThread = CurrThread.NextMutexThread;
|
|
||||||
|
|
||||||
CurrThread.NextMutexThread = null;
|
|
||||||
|
|
||||||
if (OwnerThread != null)
|
|
||||||
{
|
|
||||||
int HasListeners = OwnerThread.NextMutexThread != null ? MutexHasListenersMask : 0;
|
|
||||||
|
|
||||||
Process.Memory.WriteInt32(MutexAddress, HasListeners | OwnerThread.Handle);
|
|
||||||
|
|
||||||
Process.Scheduler.WakeUp(OwnerThread);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Process.Memory.WriteInt32(MutexAddress, 0);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CondVarWait(KThread WaitThread, long MutexAddress, long CondVarAddress, ulong Timeout)
|
|
||||||
{
|
|
||||||
KThread CurrThread = Process.ThreadArbiterList;
|
|
||||||
|
|
||||||
if (CurrThread != null)
|
|
||||||
{
|
|
||||||
bool DoInsert = CurrThread != WaitThread;
|
|
||||||
|
|
||||||
while (CurrThread.NextCondVarThread != null)
|
|
||||||
{
|
|
||||||
if (CurrThread.NextCondVarThread.Priority < WaitThread.Priority)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrThread = CurrThread.NextCondVarThread;
|
|
||||||
|
|
||||||
DoInsert &= CurrThread != WaitThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DoInsert)
|
|
||||||
{
|
|
||||||
if (WaitThread.NextCondVarThread != null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
WaitThread.NextCondVarThread = CurrThread.NextCondVarThread;
|
|
||||||
CurrThread.NextCondVarThread = WaitThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrThread.MutexAddress = MutexAddress;
|
|
||||||
CurrThread.CondVarAddress = CondVarAddress;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Process.ThreadArbiterList = WaitThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Timeout != ulong.MaxValue)
|
|
||||||
{
|
|
||||||
return Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Process.Scheduler.EnterWait(WaitThread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CondVarSignal(long CondVarAddress, int Count)
|
|
||||||
{
|
|
||||||
KThread PrevThread = null;
|
|
||||||
KThread CurrThread = Process.ThreadArbiterList;
|
|
||||||
|
|
||||||
while (CurrThread != null && (Count == -1 || Count-- > 0))
|
|
||||||
{
|
|
||||||
if (CurrThread.CondVarAddress == CondVarAddress)
|
|
||||||
{
|
|
||||||
if (PrevThread != null)
|
|
||||||
{
|
|
||||||
PrevThread.NextCondVarThread = CurrThread.NextCondVarThread;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Process.ThreadArbiterList = CurrThread.NextCondVarThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrThread.NextCondVarThread = null;
|
|
||||||
|
|
||||||
AcquireMutexValue(CurrThread.MutexAddress);
|
|
||||||
|
|
||||||
int MutexValue = Process.Memory.ReadInt32(CurrThread.MutexAddress);
|
|
||||||
|
|
||||||
MutexValue &= ~MutexHasListenersMask;
|
|
||||||
|
|
||||||
if (MutexValue == 0)
|
|
||||||
{
|
|
||||||
Process.Memory.WriteInt32(CurrThread.MutexAddress, CurrThread.Handle);
|
|
||||||
|
|
||||||
CurrThread.MutexAddress = 0;
|
|
||||||
CurrThread.CondVarAddress = 0;
|
|
||||||
|
|
||||||
CurrThread.ResetPriority();
|
|
||||||
|
|
||||||
Process.Scheduler.WakeUp(CurrThread);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
InsertWaitingMutexThread(MutexValue, CurrThread);
|
|
||||||
|
|
||||||
MutexValue |= MutexHasListenersMask;
|
|
||||||
|
|
||||||
Process.Memory.WriteInt32(CurrThread.MutexAddress, MutexValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseMutexValue(CurrThread.MutexAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
PrevThread = CurrThread;
|
|
||||||
CurrThread = CurrThread.NextCondVarThread;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InsertWaitingMutexThread(int OwnerThreadHandle, KThread WaitThread)
|
|
||||||
{
|
|
||||||
KThread CurrThread = Process.HandleTable.GetData<KThread>(OwnerThreadHandle);
|
|
||||||
|
|
||||||
if (CurrThread == null)
|
|
||||||
{
|
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Invalid thread handle 0x{OwnerThreadHandle:x8}!");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (CurrThread.NextMutexThread != null)
|
|
||||||
{
|
|
||||||
if (CurrThread == WaitThread)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrThread.NextMutexThread.Priority < WaitThread.Priority)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrThread = CurrThread.NextMutexThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrThread != WaitThread)
|
|
||||||
{
|
|
||||||
if (WaitThread.NextCondVarThread != null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
WaitThread.NextMutexThread = CurrThread.NextMutexThread;
|
|
||||||
CurrThread.NextMutexThread = WaitThread;
|
|
||||||
|
|
||||||
CurrThread.UpdatePriority();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AcquireMutexValue(long MutexAddress)
|
|
||||||
{
|
|
||||||
while (!Process.Memory.AcquireAddress(MutexAddress))
|
|
||||||
{
|
|
||||||
Thread.Yield();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReleaseMutexValue(long MutexAddress)
|
|
||||||
{
|
|
||||||
Process.Memory.ReleaseAddress(MutexAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsPointingInsideKernel(long Address)
|
|
||||||
{
|
|
||||||
return ((ulong)Address + 0x1000000000) < 0xffffff000;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsWordAddressUnaligned(long Address)
|
|
||||||
{
|
|
||||||
return (Address & 3) != 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,6 @@ using Ryujinx.Core.OsHle.Services.Nv;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle
|
namespace Ryujinx.Core.OsHle
|
||||||
{
|
{
|
||||||
|
@ -36,8 +35,6 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
public KProcessScheduler Scheduler { get; private set; }
|
public KProcessScheduler Scheduler { get; private set; }
|
||||||
|
|
||||||
public KThread ThreadArbiterList { get; set; }
|
|
||||||
|
|
||||||
public KProcessHandleTable HandleTable { get; private set; }
|
public KProcessHandleTable HandleTable { get; private set; }
|
||||||
|
|
||||||
public AppletStateMgr AppletState { get; private set; }
|
public AppletStateMgr AppletState { get; private set; }
|
||||||
|
@ -46,7 +43,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
private ConcurrentDictionary<int, AThread> TlsSlots;
|
private ConcurrentDictionary<int, AThread> TlsSlots;
|
||||||
|
|
||||||
private ConcurrentDictionary<long, KThread> Threads;
|
private ConcurrentDictionary<long, KThread> ThreadsByTpidr;
|
||||||
|
|
||||||
private List<Executable> Executables;
|
private List<Executable> Executables;
|
||||||
|
|
||||||
|
@ -74,7 +71,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
TlsSlots = new ConcurrentDictionary<int, AThread>();
|
TlsSlots = new ConcurrentDictionary<int, AThread>();
|
||||||
|
|
||||||
Threads = new ConcurrentDictionary<long, KThread>();
|
ThreadsByTpidr = new ConcurrentDictionary<long, KThread>();
|
||||||
|
|
||||||
Executables = new List<Executable>();
|
Executables = new List<Executable>();
|
||||||
|
|
||||||
|
@ -188,34 +185,34 @@ namespace Ryujinx.Core.OsHle
|
||||||
throw new ObjectDisposedException(nameof(Process));
|
throw new ObjectDisposedException(nameof(Process));
|
||||||
}
|
}
|
||||||
|
|
||||||
AThread CpuThread = new AThread(GetTranslator(), Memory, EntryPoint);
|
AThread Thread = new AThread(GetTranslator(), Memory, EntryPoint);
|
||||||
|
|
||||||
KThread Thread = new KThread(CpuThread, ProcessorId, Priority);
|
KThread KernelThread = new KThread(Thread, ProcessorId, Priority);
|
||||||
|
|
||||||
int Handle = HandleTable.OpenHandle(Thread);
|
int Handle = HandleTable.OpenHandle(KernelThread);
|
||||||
|
|
||||||
Thread.Handle = Handle;
|
KernelThread.Handle = Handle;
|
||||||
|
|
||||||
int ThreadId = GetFreeTlsSlot(CpuThread);
|
int ThreadId = GetFreeTlsSlot(Thread);
|
||||||
|
|
||||||
long Tpidr = MemoryRegions.TlsPagesAddress + ThreadId * TlsSize;
|
long Tpidr = MemoryRegions.TlsPagesAddress + ThreadId * TlsSize;
|
||||||
|
|
||||||
CpuThread.ThreadState.ProcessId = ProcessId;
|
Thread.ThreadState.ProcessId = ProcessId;
|
||||||
CpuThread.ThreadState.ThreadId = ThreadId;
|
Thread.ThreadState.ThreadId = ThreadId;
|
||||||
CpuThread.ThreadState.CntfrqEl0 = TickFreq;
|
Thread.ThreadState.CntfrqEl0 = TickFreq;
|
||||||
CpuThread.ThreadState.Tpidr = Tpidr;
|
Thread.ThreadState.Tpidr = Tpidr;
|
||||||
|
|
||||||
CpuThread.ThreadState.X0 = (ulong)ArgsPtr;
|
Thread.ThreadState.X0 = (ulong)ArgsPtr;
|
||||||
CpuThread.ThreadState.X1 = (ulong)Handle;
|
Thread.ThreadState.X1 = (ulong)Handle;
|
||||||
CpuThread.ThreadState.X31 = (ulong)StackTop;
|
Thread.ThreadState.X31 = (ulong)StackTop;
|
||||||
|
|
||||||
CpuThread.ThreadState.Break += BreakHandler;
|
Thread.ThreadState.Break += BreakHandler;
|
||||||
CpuThread.ThreadState.SvcCall += SvcHandler.SvcCall;
|
Thread.ThreadState.SvcCall += SvcHandler.SvcCall;
|
||||||
CpuThread.ThreadState.Undefined += UndefinedHandler;
|
Thread.ThreadState.Undefined += UndefinedHandler;
|
||||||
|
|
||||||
CpuThread.WorkFinished += ThreadFinished;
|
Thread.WorkFinished += ThreadFinished;
|
||||||
|
|
||||||
Threads.TryAdd(CpuThread.ThreadState.Tpidr, Thread);
|
ThreadsByTpidr.TryAdd(Thread.ThreadState.Tpidr, KernelThread);
|
||||||
|
|
||||||
return Handle;
|
return Handle;
|
||||||
}
|
}
|
||||||
|
@ -327,7 +324,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
public KThread GetThread(long Tpidr)
|
public KThread GetThread(long Tpidr)
|
||||||
{
|
{
|
||||||
if (!Threads.TryGetValue(Tpidr, out KThread Thread))
|
if (!ThreadsByTpidr.TryGetValue(Tpidr, out KThread Thread))
|
||||||
{
|
{
|
||||||
Logging.Error(LogClass.KernelScheduler, $"Thread with TPIDR 0x{Tpidr:x16} not found!");
|
Logging.Error(LogClass.KernelScheduler, $"Thread with TPIDR 0x{Tpidr:x16} not found!");
|
||||||
}
|
}
|
||||||
|
@ -335,28 +332,6 @@ namespace Ryujinx.Core.OsHle
|
||||||
return Thread;
|
return Thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<KThread> EnumerateThreadsWithMutex(long MutexAddress)
|
|
||||||
{
|
|
||||||
foreach (KThread Thread in Threads.Values.OrderBy(x => x.Priority))
|
|
||||||
{
|
|
||||||
if (Thread.MutexAddress == MutexAddress)
|
|
||||||
{
|
|
||||||
yield return Thread;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<KThread> EnumerateThreadsWithCondVar(long CondVarAddress)
|
|
||||||
{
|
|
||||||
foreach (KThread Thread in Threads.Values.OrderBy(x => x.Priority))
|
|
||||||
{
|
|
||||||
if (Thread.CondVarAddress == CondVarAddress)
|
|
||||||
{
|
|
||||||
yield return Thread;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue