Thread scheduler rewrite (#393)
* Started to rewrite the thread scheduler * Add a single core-like scheduling mode, enabled by default * Clear exclusive monitor on context switch * Add SetThreadActivity, misc fixes * Implement WaitForAddress and SignalToAddress svcs, misc fixes * Misc fixes (on SetActivity and Arbiter), other tweaks * Rebased * Add missing null check * Rename multicore key on config, fix UpdatePriorityInheritance * Make scheduling data MLQs private * nit: Ordering
This commit is contained in:
parent
33e2810ef3
commit
b8133c1997
57 changed files with 3262 additions and 1540 deletions
|
@ -68,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Event != null)
|
||||
{
|
||||
Event.WaitEvent.Reset();
|
||||
Event.Reset();
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
}
|
||||
|
@ -80,115 +80,6 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
}
|
||||
|
||||
private void SvcWaitSynchronization(AThreadState ThreadState)
|
||||
{
|
||||
long HandlesPtr = (long)ThreadState.X1;
|
||||
int HandlesCount = (int)ThreadState.X2;
|
||||
ulong Timeout = ThreadState.X3;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc,
|
||||
"HandlesPtr = 0x" + HandlesPtr .ToString("x16") + ", " +
|
||||
"HandlesCount = 0x" + HandlesCount.ToString("x8") + ", " +
|
||||
"Timeout = 0x" + Timeout .ToString("x16"));
|
||||
|
||||
if ((uint)HandlesCount > 0x40)
|
||||
{
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
|
||||
|
||||
WaitHandle[] Handles = new WaitHandle[HandlesCount + 1];
|
||||
|
||||
for (int Index = 0; Index < HandlesCount; Index++)
|
||||
{
|
||||
int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);
|
||||
|
||||
KSynchronizationObject SyncObj = Process.HandleTable.GetData<KSynchronizationObject>(Handle);
|
||||
|
||||
if (SyncObj == null)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Handles[Index] = SyncObj.WaitEvent;
|
||||
}
|
||||
|
||||
using (AutoResetEvent WaitEvent = new AutoResetEvent(false))
|
||||
{
|
||||
if (!SyncWaits.TryAdd(CurrThread, WaitEvent))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Handles[HandlesCount] = WaitEvent;
|
||||
|
||||
Process.Scheduler.Suspend(CurrThread);
|
||||
|
||||
int HandleIndex;
|
||||
|
||||
ulong Result = 0;
|
||||
|
||||
if (Timeout != ulong.MaxValue)
|
||||
{
|
||||
HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout));
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleIndex = WaitHandle.WaitAny(Handles);
|
||||
}
|
||||
|
||||
if (HandleIndex == WaitHandle.WaitTimeout)
|
||||
{
|
||||
Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
}
|
||||
else if (HandleIndex == HandlesCount)
|
||||
{
|
||||
Result = MakeError(ErrorModule.Kernel, KernelErr.Canceled);
|
||||
}
|
||||
|
||||
SyncWaits.TryRemove(CurrThread, out _);
|
||||
|
||||
Process.Scheduler.Resume(CurrThread);
|
||||
|
||||
ThreadState.X0 = Result;
|
||||
|
||||
if (Result == 0)
|
||||
{
|
||||
ThreadState.X1 = (ulong)HandleIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SvcCancelSynchronization(AThreadState ThreadState)
|
||||
{
|
||||
int ThreadHandle = (int)ThreadState.X0;
|
||||
|
||||
KThread Thread = GetThread(ThreadState.Tpidr, ThreadHandle);
|
||||
|
||||
if (Thread == null)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (SyncWaits.TryRemove(Thread, out AutoResetEvent WaitEvent))
|
||||
{
|
||||
WaitEvent.Set();
|
||||
}
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
}
|
||||
|
||||
private void SvcGetSystemTick(AThreadState ThreadState)
|
||||
{
|
||||
ThreadState.X0 = ThreadState.CntpctEl0;
|
||||
|
@ -203,7 +94,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
//TODO: Validate that app has perms to access the service, and that the service
|
||||
//actually exists, return error codes otherwise.
|
||||
KSession Session = new KSession(ServiceFactory.MakeService(Name), Name);
|
||||
KSession Session = new KSession(ServiceFactory.MakeService(System, Name), Name);
|
||||
|
||||
ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
|
||||
|
||||
|
@ -225,27 +116,38 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
(int)ThreadState.X2);
|
||||
}
|
||||
|
||||
private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, int Handle)
|
||||
private void SendSyncRequest(AThreadState ThreadState, long MessagePtr, long Size, int Handle)
|
||||
{
|
||||
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
|
||||
|
||||
byte[] CmdData = Memory.ReadBytes(CmdPtr, Size);
|
||||
byte[] MessageData = Memory.ReadBytes(MessagePtr, Size);
|
||||
|
||||
KSession Session = Process.HandleTable.GetData<KSession>(Handle);
|
||||
|
||||
if (Session != null)
|
||||
{
|
||||
Process.Scheduler.Suspend(CurrThread);
|
||||
//Process.Scheduler.Suspend(CurrThread);
|
||||
|
||||
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);
|
||||
System.CriticalSectionLock.Lock();
|
||||
|
||||
long Result = IpcHandler.IpcCall(Device, Process, Memory, Session, Cmd, CmdPtr);
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
|
||||
Thread.Yield();
|
||||
CurrentThread.SignaledObj = null;
|
||||
CurrentThread.ObjSyncResult = 0;
|
||||
|
||||
Process.Scheduler.Resume(CurrThread);
|
||||
CurrentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
IpcMessage Message = new IpcMessage(MessageData, MessagePtr);
|
||||
|
||||
ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage(
|
||||
CurrentThread,
|
||||
Session,
|
||||
Message,
|
||||
MessagePtr));
|
||||
|
||||
System.CriticalSectionLock.Unlock();
|
||||
|
||||
ThreadState.X0 = (ulong)CurrentThread.ObjSyncResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -255,6 +157,21 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
}
|
||||
|
||||
private void ProcessIpcRequest(object State)
|
||||
{
|
||||
HleIpcMessage IpcMessage = (HleIpcMessage)State;
|
||||
|
||||
IpcMessage.Thread.ObjSyncResult = (int)IpcHandler.IpcCall(
|
||||
Device,
|
||||
Process,
|
||||
Memory,
|
||||
IpcMessage.Session,
|
||||
IpcMessage.Message,
|
||||
IpcMessage.MessagePtr);
|
||||
|
||||
IpcMessage.Thread.Reschedule(ThreadSchedState.Running);
|
||||
}
|
||||
|
||||
private void SvcBreak(AThreadState ThreadState)
|
||||
{
|
||||
long Reason = (long)ThreadState.X0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue