mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-12-17 22:36:58 +00:00
Memory changes 3 (ryubing/ryujinx!202)
See merge request ryubing/ryujinx!202
This commit is contained in:
parent
ab7aeee67b
commit
92b61f9d73
43 changed files with 686 additions and 315 deletions
|
|
@ -1,3 +1,4 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.Horizon.Common;
|
||||
|
|
@ -11,6 +12,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
class KAddressArbiter
|
||||
{
|
||||
private const int HasListenersMask = 0x40000000;
|
||||
private static readonly ObjectPool<KThread[]> _threadArrayPool = new(() => []);
|
||||
|
||||
private readonly KernelContext _context;
|
||||
|
||||
|
|
@ -198,9 +200,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
{
|
||||
_context.CriticalSection.Enter();
|
||||
|
||||
WakeThreads(_condVarThreads, count, TryAcquireMutex, x => x.CondVarAddress == address);
|
||||
static bool SignalProcessWideKeyPredicate(KThread thread, ulong address)
|
||||
{
|
||||
return thread.CondVarAddress == address;
|
||||
}
|
||||
|
||||
if (!_condVarThreads.Any(x => x.CondVarAddress == address))
|
||||
int validThreads = WakeThreads(_condVarThreads, count, TryAcquireMutex, SignalProcessWideKeyPredicate, address);
|
||||
|
||||
if (validThreads == 0)
|
||||
{
|
||||
KernelTransfer.KernelToUser(address, 0);
|
||||
}
|
||||
|
|
@ -480,9 +487,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
// or negative. It is incremented if there are no threads waiting.
|
||||
int waitingCount = 0;
|
||||
|
||||
foreach (KThread thread in _arbiterThreads.Where(x => x.MutexAddress == address))
|
||||
foreach (KThread thread in _arbiterThreads)
|
||||
{
|
||||
if (++waitingCount >= count)
|
||||
if (thread.MutexAddress == address &&
|
||||
++waitingCount >= count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -553,23 +561,55 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
thread.WaitingInArbitration = false;
|
||||
}
|
||||
|
||||
WakeThreads(_arbiterThreads, count, RemoveArbiterThread, x => x.MutexAddress == address);
|
||||
static bool ArbiterThreadPredecate(KThread thread, ulong address)
|
||||
{
|
||||
return thread.MutexAddress == address;
|
||||
}
|
||||
|
||||
WakeThreads(_arbiterThreads, count, RemoveArbiterThread, ArbiterThreadPredecate, address);
|
||||
}
|
||||
|
||||
private static void WakeThreads(
|
||||
private static int WakeThreads(
|
||||
List<KThread> threads,
|
||||
int count,
|
||||
Action<KThread> removeCallback,
|
||||
Func<KThread, bool> predicate)
|
||||
Func<KThread, ulong, bool> predicate,
|
||||
ulong address = 0)
|
||||
{
|
||||
IOrderedEnumerable<KThread> candidates = threads.Where(predicate).OrderBy(x => x.DynamicPriority);
|
||||
KThread[] toSignal = (count > 0 ? candidates.Take(count) : candidates).ToArray();
|
||||
KThread[] candidates = _threadArrayPool.Allocate();
|
||||
if (candidates.Length < threads.Count)
|
||||
{
|
||||
Array.Resize(ref candidates, threads.Count);
|
||||
}
|
||||
|
||||
int validCount = 0;
|
||||
|
||||
for (int i = 0; i < threads.Count; i++)
|
||||
{
|
||||
if (predicate(threads[i], address))
|
||||
{
|
||||
candidates[validCount++] = threads[i];
|
||||
}
|
||||
}
|
||||
|
||||
Span<KThread> candidatesSpan = candidates.AsSpan(..validCount);
|
||||
|
||||
candidatesSpan.Sort((x, y) => (x.DynamicPriority.CompareTo(y.DynamicPriority)));
|
||||
|
||||
foreach (KThread thread in toSignal)
|
||||
if (count > 0)
|
||||
{
|
||||
candidatesSpan = candidatesSpan[..Math.Min(count, candidatesSpan.Length)];
|
||||
}
|
||||
|
||||
foreach (KThread thread in candidatesSpan)
|
||||
{
|
||||
removeCallback(thread);
|
||||
threads.Remove(thread);
|
||||
}
|
||||
|
||||
_threadArrayPool.Release(candidates);
|
||||
|
||||
return validCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
public KThreadContext ThreadContext { get; private set; }
|
||||
|
||||
public int DynamicPriority { get; set; }
|
||||
public ulong AffinityMask { get; set; }
|
||||
public int DynamicPriority { get; private set; }
|
||||
public ulong AffinityMask { get; private set; }
|
||||
|
||||
public ulong ThreadUid { get; private set; }
|
||||
|
||||
|
|
@ -83,18 +83,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
public long LastScheduledTime { get; set; }
|
||||
|
||||
public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
|
||||
public readonly LinkedListNode<KThread>[] SiblingsPerCore;
|
||||
|
||||
public LinkedList<KThread> Withholder { get; set; }
|
||||
public LinkedListNode<KThread> WithholderNode { get; set; }
|
||||
public readonly LinkedListNode<KThread> WithholderNode;
|
||||
|
||||
public LinkedListNode<KThread> ProcessListNode { get; set; }
|
||||
public readonly LinkedListNode<KThread> ProcessListNode;
|
||||
|
||||
private readonly LinkedList<KThread> _mutexWaiters;
|
||||
private LinkedListNode<KThread> _mutexWaiterNode;
|
||||
private readonly LinkedListNode<KThread> _mutexWaiterNode;
|
||||
|
||||
private readonly LinkedList<KThread> _pinnedWaiters;
|
||||
private LinkedListNode<KThread> _pinnedWaiterNode;
|
||||
private readonly LinkedListNode<KThread> _pinnedWaiterNode;
|
||||
|
||||
public KThread MutexOwner { get; private set; }
|
||||
|
||||
|
|
@ -1070,11 +1070,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
if (nextPrio != null)
|
||||
{
|
||||
thread._mutexWaiterNode = _mutexWaiters.AddBefore(nextPrio, thread);
|
||||
_mutexWaiters.AddBefore(nextPrio, thread._mutexWaiterNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
thread._mutexWaiterNode = _mutexWaiters.AddLast(thread);
|
||||
_mutexWaiters.AddLast(thread._mutexWaiterNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue