From 48278905d1470f89be31668c738397f569af156a Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 9 Dec 2020 19:20:05 -0300 Subject: Rewrite scheduler context switch code (#1786) * Rewrite scheduler context switch code * Fix race in UnmapIpcRestorePermission * Fix thread exit issue that could leave the scheduler in a invalid state * Change context switch method to not wait on guest thread, remove spin wait, use SignalAndWait to pass control * Remove multi-core setting (it is always on now) * Re-enable assert * Remove multicore from default config and schema * Fix race in KTimeManager --- Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs | 15 ++++- Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs | 87 +++++++++++-------------- Ryujinx.HLE/HOS/Kernel/Common/KernelTransfer.cs | 10 +-- 3 files changed, 54 insertions(+), 58 deletions(-) (limited to 'Ryujinx.HLE/HOS/Kernel/Common') diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs b/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs index 812cbd30..a94b280f 100644 --- a/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs +++ b/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.Threading; namespace Ryujinx.HLE.HOS.Kernel.Common @@ -47,17 +48,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Common public void IncrementReferenceCount() { - Interlocked.Increment(ref _referenceCount); + int newRefCount = Interlocked.Increment(ref _referenceCount); + + Debug.Assert(newRefCount >= 2); } public void DecrementReferenceCount() { - if (Interlocked.Decrement(ref _referenceCount) == 0) + int newRefCount = Interlocked.Decrement(ref _referenceCount); + + Debug.Assert(newRefCount >= 0); + + if (newRefCount == 0) { Destroy(); } } - protected virtual void Destroy() { } + protected virtual void Destroy() + { + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs b/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs index 8273520f..f7a1c24a 100644 --- a/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs @@ -10,9 +10,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common { private class WaitingObject { - public IKFutureSchedulerObject Object { get; private set; } - - public long TimePoint { get; private set; } + public IKFutureSchedulerObject Object { get; } + public long TimePoint { get; } public WaitingObject(IKFutureSchedulerObject schedulerObj, long timePoint) { @@ -21,16 +20,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Common } } - private List _waitingObjects; - + private readonly KernelContext _context; + private readonly List _waitingObjects; private AutoResetEvent _waitEvent; - private bool _keepRunning; - public KTimeManager() + public KTimeManager(KernelContext context) { + _context = context; _waitingObjects = new List(); - _keepRunning = true; Thread work = new Thread(WaitAndCheckScheduledObjects) @@ -45,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common { long timePoint = PerformanceCounter.ElapsedMilliseconds + ConvertNanosecondsToMilliseconds(timeout); - lock (_waitingObjects) + lock (_context.CriticalSection.Lock) { _waitingObjects.Add(new WaitingObject(schedulerObj, timePoint)); } @@ -53,33 +51,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Common _waitEvent.Set(); } - public static long ConvertNanosecondsToMilliseconds(long time) - { - time /= 1000000; - - if ((ulong)time > int.MaxValue) - { - return int.MaxValue; - } - - return time; - } - - public static long ConvertMillisecondsToNanoseconds(long time) - { - return time * 1000000; - } - - public static long ConvertMillisecondsToTicks(long time) - { - return time * 19200; - } - - public void UnscheduleFutureInvocation(IKFutureSchedulerObject Object) + public void UnscheduleFutureInvocation(IKFutureSchedulerObject schedulerObj) { - lock (_waitingObjects) + lock (_context.CriticalSection.Lock) { - _waitingObjects.RemoveAll(x => x.Object == Object); + _waitingObjects.RemoveAll(x => x.Object == schedulerObj); } } @@ -91,7 +67,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common { WaitingObject next; - lock (_waitingObjects) + lock (_context.CriticalSection.Lock) { next = _waitingObjects.OrderBy(x => x.TimePoint).FirstOrDefault(); } @@ -109,16 +85,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Common if (timeUp) { - lock (_waitingObjects) + lock (_context.CriticalSection.Lock) { - timeUp = _waitingObjects.Remove(next); + if (_waitingObjects.Remove(next)) + { + next.Object.TimeUp(); + } } } - - if (timeUp) - { - next.Object.TimeUp(); - } } else { @@ -128,19 +102,32 @@ namespace Ryujinx.HLE.HOS.Kernel.Common } } - public void Dispose() + public static long ConvertNanosecondsToMilliseconds(long time) + { + time /= 1000000; + + if ((ulong)time > int.MaxValue) + { + return int.MaxValue; + } + + return time; + } + + public static long ConvertMillisecondsToNanoseconds(long time) { - Dispose(true); + return time * 1000000; } - protected virtual void Dispose(bool disposing) + public static long ConvertHostTicksToTicks(long time) { - if (disposing) - { - _keepRunning = false; + return (long)((time / (double)PerformanceCounter.TicksPerSecond) * 19200000.0); + } - _waitEvent?.Set(); - } + public void Dispose() + { + _keepRunning = false; + _waitEvent?.Set(); } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KernelTransfer.cs b/Ryujinx.HLE/HOS/Kernel/Common/KernelTransfer.cs index d57ca481..3002b6a9 100644 --- a/Ryujinx.HLE/HOS/Kernel/Common/KernelTransfer.cs +++ b/Ryujinx.HLE/HOS/Kernel/Common/KernelTransfer.cs @@ -8,7 +8,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common { public static bool UserToKernelInt32(KernelContext context, ulong address, out int value) { - KProcess currentProcess = context.Scheduler.GetCurrentProcess(); + KProcess currentProcess = KernelStatic.GetCurrentProcess(); if (currentProcess.CpuMemory.IsMapped(address) && currentProcess.CpuMemory.IsMapped(address + 3)) @@ -25,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common public static bool UserToKernelInt32Array(KernelContext context, ulong address, Span values) { - KProcess currentProcess = context.Scheduler.GetCurrentProcess(); + KProcess currentProcess = KernelStatic.GetCurrentProcess(); for (int index = 0; index < values.Length; index++, address += 4) { @@ -45,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common public static bool UserToKernelString(KernelContext context, ulong address, int size, out string value) { - KProcess currentProcess = context.Scheduler.GetCurrentProcess(); + KProcess currentProcess = KernelStatic.GetCurrentProcess(); if (currentProcess.CpuMemory.IsMapped(address) && currentProcess.CpuMemory.IsMapped(address + (ulong)size - 1)) @@ -62,7 +62,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common public static bool KernelToUserInt32(KernelContext context, ulong address, int value) { - KProcess currentProcess = context.Scheduler.GetCurrentProcess(); + KProcess currentProcess = KernelStatic.GetCurrentProcess(); if (currentProcess.CpuMemory.IsMapped(address) && currentProcess.CpuMemory.IsMapped(address + 3)) @@ -77,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common public static bool KernelToUserInt64(KernelContext context, ulong address, long value) { - KProcess currentProcess = context.Scheduler.GetCurrentProcess(); + KProcess currentProcess = KernelStatic.GetCurrentProcess(); if (currentProcess.CpuMemory.IsMapped(address) && currentProcess.CpuMemory.IsMapped(address + 7)) -- cgit v1.2.3