Some fixes

This commit is contained in:
gdkchan 2018-04-21 13:19:06 -03:00
parent 5858b06fc7
commit 3fae7e30e7
4 changed files with 146 additions and 136 deletions

View file

@ -18,7 +18,7 @@ namespace Ryujinx.Core.OsHle.Handles
private int DesiredPriority;
public int Handle { get; set; }
public int WaitHandle { get; set; }
public int ThreadId => Thread.ThreadId;

View file

@ -17,6 +17,8 @@ namespace Ryujinx.Core.OsHle.Kernel
private Process Process;
private AMemory Memory;
private object CondVarLock;
private HashSet<(HSharedMem, long)> MappedSharedMems;
private ulong CurrentHeapSize;
@ -67,6 +69,8 @@ namespace Ryujinx.Core.OsHle.Kernel
this.Process = Process;
this.Memory = Process.Memory;
CondVarLock = new object();
MappedSharedMems = new HashSet<(HSharedMem, long)>();
}

View file

@ -13,9 +13,9 @@ namespace Ryujinx.Core.OsHle.Kernel
private void SvcArbitrateLock(AThreadState ThreadState)
{
int OwnerThreadHandle = (int)ThreadState.X0;
long MutexAddress = (long)ThreadState.X1;
int RequestingThreadHandle = (int)ThreadState.X2;
int OwnerThreadHandle = (int)ThreadState.X0;
long MutexAddress = (long)ThreadState.X1;
int WaitThreadHandle = (int)ThreadState.X2;
if (IsPointingInsideKernel(MutexAddress))
{
@ -46,18 +46,20 @@ namespace Ryujinx.Core.OsHle.Kernel
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);
return;
}
MutexLock(MutexAddress, RequestingThread, OwnerThreadHandle);
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
MutexLock(CurrThread, WaitThread, OwnerThreadHandle, WaitThreadHandle, MutexAddress);
ThreadState.X0 = 0;
}
@ -128,9 +130,11 @@ namespace Ryujinx.Core.OsHle.Kernel
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);
@ -152,7 +156,12 @@ namespace Ryujinx.Core.OsHle.Kernel
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);
@ -161,11 +170,12 @@ namespace Ryujinx.Core.OsHle.Kernel
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)
@ -177,11 +187,6 @@ namespace Ryujinx.Core.OsHle.Kernel
return false;
}
CurrThread.MutexAddress = 0;
CurrThread.CondVarAddress = 0;
CurrThread.ResetPriority();
KThread OwnerThread = CurrThread.NextMutexThread;
CurrThread.NextMutexThread = null;
@ -190,7 +195,13 @@ namespace Ryujinx.Core.OsHle.Kernel
{
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);
@ -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;
DoInsert &= CurrThread != WaitThread;
}
if (DoInsert)
{
if (WaitThread.NextCondVarThread != null)
if (DoInsert)
{
throw new InvalidOperationException();
if (WaitThread.NextCondVarThread != null)
{
throw new InvalidOperationException();
}
WaitThread.NextCondVarThread = CurrThread.NextCondVarThread;
CurrThread.NextCondVarThread = WaitThread;
}
WaitThread.NextCondVarThread = CurrThread.NextCondVarThread;
CurrThread.NextCondVarThread = WaitThread;
}
CurrThread.MutexAddress = MutexAddress;
CurrThread.CondVarAddress = CondVarAddress;
}
else
{
Process.ThreadArbiterList = WaitThread;
else
{
Process.ThreadArbiterList = WaitThread;
}
}
if (Timeout != ulong.MaxValue)
@ -255,95 +275,106 @@ namespace Ryujinx.Core.OsHle.Kernel
private void CondVarSignal(long CondVarAddress, int Count)
{
KThread PrevThread = null;
KThread CurrThread = Process.ThreadArbiterList;
while (CurrThread != null && (Count == -1 || Count-- > 0))
lock (CondVarLock)
{
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;
}
else
{
Process.ThreadArbiterList = CurrThread.NextCondVarThread;
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.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;
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;
}
PrevThread = CurrThread;
CurrThread = CurrThread.NextCondVarThread;
}
}
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}!");
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();
}
}

View file

@ -10,7 +10,6 @@ using Ryujinx.Core.OsHle.Services.Nv;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Ryujinx.Core.OsHle
{
@ -194,8 +193,6 @@ namespace Ryujinx.Core.OsHle
int Handle = HandleTable.OpenHandle(Thread);
Thread.Handle = Handle;
int ThreadId = GetFreeTlsSlot(CpuThread);
long Tpidr = MemoryRegions.TlsPagesAddress + ThreadId * TlsSize;
@ -335,28 +332,6 @@ namespace Ryujinx.Core.OsHle
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()
{
Dispose(true);