Some fixes

This commit is contained in:
gdkchan 2018-04-21 13:19:06 -03:00
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; private int DesiredPriority;
public int Handle { get; set; } public int WaitHandle { get; set; }
public int ThreadId => Thread.ThreadId; public int ThreadId => Thread.ThreadId;

View file

@ -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)>();
} }

View file

@ -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();
} }
} }

View file

@ -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);