Some fixes
This commit is contained in:
parent
5858b06fc7
commit
3fae7e30e7
4 changed files with 146 additions and 136 deletions
|
@ -18,7 +18,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
||||||
|
|
||||||
private int DesiredPriority;
|
private int DesiredPriority;
|
||||||
|
|
||||||
public int Handle { get; set; }
|
public int WaitHandle { get; set; }
|
||||||
|
|
||||||
public int ThreadId => Thread.ThreadId;
|
public int ThreadId => Thread.ThreadId;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
private Process Process;
|
private Process Process;
|
||||||
private AMemory Memory;
|
private AMemory Memory;
|
||||||
|
|
||||||
|
private object CondVarLock;
|
||||||
|
|
||||||
private HashSet<(HSharedMem, long)> MappedSharedMems;
|
private HashSet<(HSharedMem, long)> MappedSharedMems;
|
||||||
|
|
||||||
private ulong CurrentHeapSize;
|
private ulong CurrentHeapSize;
|
||||||
|
@ -67,6 +69,8 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
this.Process = Process;
|
this.Process = Process;
|
||||||
this.Memory = Process.Memory;
|
this.Memory = Process.Memory;
|
||||||
|
|
||||||
|
CondVarLock = new object();
|
||||||
|
|
||||||
MappedSharedMems = new HashSet<(HSharedMem, long)>();
|
MappedSharedMems = new HashSet<(HSharedMem, long)>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,9 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
|
|
||||||
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 WaitThreadHandle = (int)ThreadState.X2;
|
||||||
|
|
||||||
if (IsPointingInsideKernel(MutexAddress))
|
if (IsPointingInsideKernel(MutexAddress))
|
||||||
{
|
{
|
||||||
|
@ -46,18 +46,20 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KThread RequestingThread = Process.HandleTable.GetData<KThread>(RequestingThreadHandle);
|
KThread WaitThread = Process.HandleTable.GetData<KThread>(WaitThreadHandle);
|
||||||
|
|
||||||
if (RequestingThread == null)
|
if (WaitThread == null)
|
||||||
{
|
{
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Invalid requesting thread handle 0x{RequestingThreadHandle:x8}!");
|
Logging.Warn(LogClass.KernelSvc, $"Invalid requesting thread handle 0x{WaitThreadHandle:x8}!");
|
||||||
|
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MutexLock(MutexAddress, RequestingThread, OwnerThreadHandle);
|
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
|
||||||
|
|
||||||
|
MutexLock(CurrThread, WaitThread, OwnerThreadHandle, WaitThreadHandle, MutexAddress);
|
||||||
|
|
||||||
ThreadState.X0 = 0;
|
ThreadState.X0 = 0;
|
||||||
}
|
}
|
||||||
|
@ -128,9 +130,11 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MutexUnlock(Process.GetThread(ThreadState.Tpidr), MutexAddress);
|
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
|
||||||
|
|
||||||
if (!CondVarWait(Thread, MutexAddress, CondVarAddress, Timeout))
|
MutexUnlock(CurrThread, MutexAddress);
|
||||||
|
|
||||||
|
if (!CondVarWait(CurrThread, ThreadHandle, MutexAddress, CondVarAddress, Timeout))
|
||||||
{
|
{
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||||
|
|
||||||
|
@ -152,7 +156,12 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
ThreadState.X0 = 0;
|
ThreadState.X0 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MutexLock(long MutexAddress, KThread RequestingThread, int OwnerThreadHandle)
|
private void MutexLock(
|
||||||
|
KThread CurrThread,
|
||||||
|
KThread WaitThread,
|
||||||
|
int OwnerThreadHandle,
|
||||||
|
int WaitThreadHandle,
|
||||||
|
long MutexAddress)
|
||||||
{
|
{
|
||||||
int MutexValue = Process.Memory.ReadInt32(MutexAddress);
|
int MutexValue = Process.Memory.ReadInt32(MutexAddress);
|
||||||
|
|
||||||
|
@ -161,11 +170,12 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertWaitingMutexThread(OwnerThreadHandle, RequestingThread);
|
CurrThread.WaitHandle = WaitThreadHandle;
|
||||||
|
CurrThread.MutexAddress = MutexAddress;
|
||||||
|
|
||||||
RequestingThread.MutexAddress = MutexAddress;
|
InsertWaitingMutexThread(OwnerThreadHandle, WaitThread);
|
||||||
|
|
||||||
Process.Scheduler.EnterWait(RequestingThread);
|
Process.Scheduler.EnterWait(WaitThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool MutexUnlock(KThread CurrThread, long MutexAddress)
|
private bool MutexUnlock(KThread CurrThread, long MutexAddress)
|
||||||
|
@ -177,11 +187,6 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrThread.MutexAddress = 0;
|
|
||||||
CurrThread.CondVarAddress = 0;
|
|
||||||
|
|
||||||
CurrThread.ResetPriority();
|
|
||||||
|
|
||||||
KThread OwnerThread = CurrThread.NextMutexThread;
|
KThread OwnerThread = CurrThread.NextMutexThread;
|
||||||
|
|
||||||
CurrThread.NextMutexThread = null;
|
CurrThread.NextMutexThread = null;
|
||||||
|
@ -190,7 +195,13 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
{
|
{
|
||||||
int HasListeners = OwnerThread.NextMutexThread != null ? MutexHasListenersMask : 0;
|
int HasListeners = OwnerThread.NextMutexThread != null ? MutexHasListenersMask : 0;
|
||||||
|
|
||||||
Process.Memory.WriteInt32(MutexAddress, HasListeners | OwnerThread.Handle);
|
Process.Memory.WriteInt32(MutexAddress, HasListeners | OwnerThread.WaitHandle);
|
||||||
|
|
||||||
|
OwnerThread.WaitHandle = 0;
|
||||||
|
OwnerThread.MutexAddress = 0;
|
||||||
|
OwnerThread.CondVarAddress = 0;
|
||||||
|
|
||||||
|
OwnerThread.ResetPriority();
|
||||||
|
|
||||||
Process.Scheduler.WakeUp(OwnerThread);
|
Process.Scheduler.WakeUp(OwnerThread);
|
||||||
|
|
||||||
|
@ -204,43 +215,52 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CondVarWait(KThread WaitThread, long MutexAddress, long CondVarAddress, ulong Timeout)
|
private bool CondVarWait(
|
||||||
|
KThread WaitThread,
|
||||||
|
int WaitThreadHandle,
|
||||||
|
long MutexAddress,
|
||||||
|
long CondVarAddress,
|
||||||
|
ulong Timeout)
|
||||||
{
|
{
|
||||||
KThread CurrThread = Process.ThreadArbiterList;
|
WaitThread.WaitHandle = WaitThreadHandle;
|
||||||
|
WaitThread.MutexAddress = MutexAddress;
|
||||||
|
WaitThread.CondVarAddress = CondVarAddress;
|
||||||
|
|
||||||
if (CurrThread != null)
|
lock (CondVarLock)
|
||||||
{
|
{
|
||||||
bool DoInsert = CurrThread != WaitThread;
|
KThread CurrThread = Process.ThreadArbiterList;
|
||||||
|
|
||||||
while (CurrThread.NextCondVarThread != null)
|
if (CurrThread != null)
|
||||||
{
|
{
|
||||||
if (CurrThread.NextCondVarThread.Priority < WaitThread.Priority)
|
bool DoInsert = CurrThread != WaitThread;
|
||||||
|
|
||||||
|
while (CurrThread.NextCondVarThread != null)
|
||||||
{
|
{
|
||||||
break;
|
if (CurrThread.NextCondVarThread.Priority < WaitThread.Priority)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrThread = CurrThread.NextCondVarThread;
|
||||||
|
|
||||||
|
DoInsert &= CurrThread != WaitThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrThread = CurrThread.NextCondVarThread;
|
if (DoInsert)
|
||||||
|
|
||||||
DoInsert &= CurrThread != WaitThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DoInsert)
|
|
||||||
{
|
|
||||||
if (WaitThread.NextCondVarThread != null)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
if (WaitThread.NextCondVarThread != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitThread.NextCondVarThread = CurrThread.NextCondVarThread;
|
||||||
|
CurrThread.NextCondVarThread = WaitThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitThread.NextCondVarThread = CurrThread.NextCondVarThread;
|
|
||||||
CurrThread.NextCondVarThread = WaitThread;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
CurrThread.MutexAddress = MutexAddress;
|
{
|
||||||
CurrThread.CondVarAddress = CondVarAddress;
|
Process.ThreadArbiterList = WaitThread;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Process.ThreadArbiterList = WaitThread;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Timeout != ulong.MaxValue)
|
if (Timeout != ulong.MaxValue)
|
||||||
|
@ -255,95 +275,106 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
|
|
||||||
private void CondVarSignal(long CondVarAddress, int Count)
|
private void CondVarSignal(long CondVarAddress, int Count)
|
||||||
{
|
{
|
||||||
KThread PrevThread = null;
|
lock (CondVarLock)
|
||||||
KThread CurrThread = Process.ThreadArbiterList;
|
|
||||||
|
|
||||||
while (CurrThread != null && (Count == -1 || Count-- > 0))
|
|
||||||
{
|
{
|
||||||
if (CurrThread.CondVarAddress == CondVarAddress)
|
KThread PrevThread = null;
|
||||||
|
KThread CurrThread = Process.ThreadArbiterList;
|
||||||
|
|
||||||
|
while (CurrThread != null && (Count == -1 || Count > 0))
|
||||||
{
|
{
|
||||||
if (PrevThread != null)
|
if (CurrThread.CondVarAddress == CondVarAddress)
|
||||||
{
|
{
|
||||||
PrevThread.NextCondVarThread = CurrThread.NextCondVarThread;
|
if (PrevThread != null)
|
||||||
}
|
{
|
||||||
else
|
PrevThread.NextCondVarThread = CurrThread.NextCondVarThread;
|
||||||
{
|
}
|
||||||
Process.ThreadArbiterList = 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.WaitHandle);
|
||||||
|
|
||||||
|
CurrThread.WaitHandle = 0;
|
||||||
|
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);
|
||||||
|
|
||||||
|
Count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrThread.NextCondVarThread = null;
|
PrevThread = CurrThread;
|
||||||
|
CurrThread = CurrThread.NextCondVarThread;
|
||||||
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)
|
private void InsertWaitingMutexThread(int OwnerThreadHandle, KThread WaitThread)
|
||||||
{
|
{
|
||||||
KThread CurrThread = Process.HandleTable.GetData<KThread>(OwnerThreadHandle);
|
KThread OwnerThread = Process.HandleTable.GetData<KThread>(OwnerThreadHandle);
|
||||||
|
|
||||||
if (CurrThread == null)
|
if (OwnerThread == null)
|
||||||
{
|
{
|
||||||
Logging.Warn(LogClass.KernelSvc, $"Invalid thread handle 0x{OwnerThreadHandle:x8}!");
|
Logging.Warn(LogClass.KernelSvc, $"Invalid thread handle 0x{OwnerThreadHandle:x8}!");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (CurrThread.NextMutexThread != null)
|
lock (OwnerThread)
|
||||||
{
|
{
|
||||||
if (CurrThread == WaitThread)
|
KThread CurrThread = OwnerThread;
|
||||||
|
|
||||||
|
while (CurrThread.NextMutexThread != null)
|
||||||
{
|
{
|
||||||
return;
|
if (CurrThread == WaitThread)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CurrThread.NextMutexThread.Priority < WaitThread.Priority)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrThread = CurrThread.NextMutexThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrThread.NextMutexThread.Priority < WaitThread.Priority)
|
if (CurrThread != WaitThread)
|
||||||
{
|
{
|
||||||
break;
|
if (WaitThread.NextCondVarThread != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitThread.NextMutexThread = CurrThread.NextMutexThread;
|
||||||
|
CurrThread.NextMutexThread = WaitThread;
|
||||||
|
|
||||||
|
CurrThread.UpdatePriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrThread = CurrThread.NextMutexThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrThread != WaitThread)
|
|
||||||
{
|
|
||||||
if (WaitThread.NextCondVarThread != null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
WaitThread.NextMutexThread = CurrThread.NextMutexThread;
|
|
||||||
CurrThread.NextMutexThread = WaitThread;
|
|
||||||
|
|
||||||
CurrThread.UpdatePriority();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -194,8 +193,6 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
int Handle = HandleTable.OpenHandle(Thread);
|
int Handle = HandleTable.OpenHandle(Thread);
|
||||||
|
|
||||||
Thread.Handle = Handle;
|
|
||||||
|
|
||||||
int ThreadId = GetFreeTlsSlot(CpuThread);
|
int ThreadId = GetFreeTlsSlot(CpuThread);
|
||||||
|
|
||||||
long Tpidr = MemoryRegions.TlsPagesAddress + ThreadId * TlsSize;
|
long Tpidr = MemoryRegions.TlsPagesAddress + ThreadId * TlsSize;
|
||||||
|
@ -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