Improve kernel WaitSynchronization syscall implementation (#1362)
This commit is contained in:
parent
88619d71b8
commit
20774dab14
@ -1,5 +1,6 @@
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||
{
|
||||
@ -22,7 +23,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool UserToKernelInt32Array(KernelContext context, ulong address, int[] values)
|
||||
public static bool UserToKernelInt32Array(KernelContext context, ulong address, Span<int> values)
|
||||
{
|
||||
KProcess currentProcess = context.Scheduler.GetCurrentProcess();
|
||||
|
||||
|
@ -8,6 +8,7 @@ using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
@ -2139,30 +2140,84 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
handleIndex = 0;
|
||||
|
||||
if ((uint)handlesCount > 0x40)
|
||||
if ((uint)handlesCount > KThread.MaxWaitSyncObjects)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
||||
List<KSynchronizationObject> syncObjs = new List<KSynchronizationObject>();
|
||||
KThread currentThread = _context.Scheduler.GetCurrentThread();
|
||||
|
||||
KProcess process = _context.Scheduler.GetCurrentProcess();
|
||||
var syncObjs = new Span<KSynchronizationObject>(currentThread.WaitSyncObjects).Slice(0, handlesCount);
|
||||
|
||||
for (int index = 0; index < handlesCount; index++)
|
||||
if (handlesCount != 0)
|
||||
{
|
||||
int handle = process.CpuMemory.Read<int>(handlesPtr + (ulong)index * 4);
|
||||
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
||||
|
||||
KSynchronizationObject syncObj = process.HandleTable.GetObject<KSynchronizationObject>(handle);
|
||||
if (currentProcess.MemoryManager.AddrSpaceStart > handlesPtr)
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
long handlesSize = handlesCount * 4;
|
||||
|
||||
if (handlesPtr + (ulong)handlesSize <= handlesPtr)
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
if (handlesPtr + (ulong)handlesSize - 1 > currentProcess.MemoryManager.AddrSpaceEnd - 1)
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
Span<int> handles = new Span<int>(currentThread.WaitSyncHandles).Slice(0, handlesCount);
|
||||
|
||||
if (!KernelTransfer.UserToKernelInt32Array(_context, handlesPtr, handles))
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
int processedHandles = 0;
|
||||
|
||||
for (; processedHandles < handlesCount; processedHandles++)
|
||||
{
|
||||
KSynchronizationObject syncObj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[processedHandles]);
|
||||
|
||||
if (syncObj == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
syncObjs.Add(syncObj);
|
||||
syncObjs[processedHandles] = syncObj;
|
||||
|
||||
syncObj.IncrementReferenceCount();
|
||||
}
|
||||
|
||||
return _context.Synchronization.WaitFor(syncObjs.ToArray(), timeout, out handleIndex);
|
||||
if (processedHandles != handlesCount)
|
||||
{
|
||||
// One or more handles are invalid.
|
||||
for (int index = 0; index < processedHandles; index++)
|
||||
{
|
||||
currentThread.WaitSyncObjects[index].DecrementReferenceCount();
|
||||
}
|
||||
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
KernelResult result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex);
|
||||
|
||||
if (result == KernelResult.PortRemoteClosed)
|
||||
{
|
||||
result = KernelResult.Success;
|
||||
}
|
||||
|
||||
for (int index = 0; index < handlesCount; index++)
|
||||
{
|
||||
currentThread.WaitSyncObjects[index].DecrementReferenceCount();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult CancelSynchronization(int handle)
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
@ -12,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public KernelResult WaitFor(KSynchronizationObject[] syncObjs, long timeout, out int handleIndex)
|
||||
public KernelResult WaitFor(Span<KSynchronizationObject> syncObjs, long timeout, out int handleIndex)
|
||||
{
|
||||
handleIndex = 0;
|
||||
|
||||
|
@ -12,6 +12,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
{
|
||||
class KThread : KSynchronizationObject, IKFutureSchedulerObject
|
||||
{
|
||||
public const int MaxWaitSyncObjects = 64;
|
||||
|
||||
private int _hostThreadRunning;
|
||||
|
||||
public Thread HostThread { get; private set; }
|
||||
@ -39,6 +41,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
public ulong TlsAddress => _tlsAddress;
|
||||
public ulong TlsDramAddress { get; private set; }
|
||||
|
||||
public KSynchronizationObject[] WaitSyncObjects { get; }
|
||||
public int[] WaitSyncHandles { get; }
|
||||
|
||||
public long LastScheduledTime { get; set; }
|
||||
|
||||
public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
|
||||
@ -96,6 +101,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
_scheduler = KernelContext.Scheduler;
|
||||
_schedulingData = KernelContext.Scheduler.SchedulingData;
|
||||
|
||||
WaitSyncObjects = new KSynchronizationObject[MaxWaitSyncObjects];
|
||||
WaitSyncHandles = new int[MaxWaitSyncObjects];
|
||||
|
||||
SiblingsPerCore = new LinkedListNode<KThread>[KScheduler.CpuCoresCount];
|
||||
|
||||
_mutexWaiters = new LinkedList<KThread>();
|
||||
|
Loading…
Reference in New Issue
Block a user