From 055ac70eaa46670cb7c424e97eda691bc7cc34db Mon Sep 17 00:00:00 2001 From: svc64 Date: Fri, 17 Nov 2023 19:15:37 +0200 Subject: [PATCH] Kill command - stop emulation --- src/Ryujinx.Gtk3/UI/MainWindow.cs | 9 ++++----- src/Ryujinx.Gtk3/UI/RendererWidgetBase.cs | 15 +++++++-------- src/Ryujinx.HLE/Debugger/Debugger.cs | 2 ++ src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs | 6 ++++-- src/Ryujinx.HLE/Switch.cs | 6 ++++++ src/Ryujinx/AppHost.cs | 15 ++++++--------- 6 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/Ryujinx.Gtk3/UI/MainWindow.cs b/src/Ryujinx.Gtk3/UI/MainWindow.cs index fe3414fa1..12c42f255 100644 --- a/src/Ryujinx.Gtk3/UI/MainWindow.cs +++ b/src/Ryujinx.Gtk3/UI/MainWindow.cs @@ -1076,9 +1076,11 @@ namespace Ryujinx.UI RendererWidget.WaitEvent.WaitOne(); RendererWidget.Start(); + _pauseEmulation.Sensitive = false; + _resumeEmulation.Sensitive = false; + UpdateMenuItem.Sensitive = true; _emulationContext.Dispose(); - _deviceExitStatus.Set(); // NOTE: Everything that is here will not be executed when you close the UI. Application.Invoke(delegate @@ -1173,7 +1175,7 @@ namespace Ryujinx.UI RendererWidget.Exit(); // Wait for the other thread to dispose the HLE context before exiting. - _deviceExitStatus.WaitOne(); + _emulationContext.ExitStatus.WaitOne(); RendererWidget.Dispose(); } } @@ -1511,9 +1513,6 @@ namespace Ryujinx.UI UpdateGameMetadata(_emulationContext.Processes.ActiveApplication.ProgramIdText); } - _pauseEmulation.Sensitive = false; - _resumeEmulation.Sensitive = false; - UpdateMenuItem.Sensitive = true; RendererWidget?.Exit(); } diff --git a/src/Ryujinx.Gtk3/UI/RendererWidgetBase.cs b/src/Ryujinx.Gtk3/UI/RendererWidgetBase.cs index 0e636792d..62dacc5ec 100644 --- a/src/Ryujinx.Gtk3/UI/RendererWidgetBase.cs +++ b/src/Ryujinx.Gtk3/UI/RendererWidgetBase.cs @@ -49,7 +49,6 @@ namespace Ryujinx.UI public static event EventHandler StatusUpdatedEvent; - private bool _isActive; private bool _isStopped; private bool _toggleFullscreen; @@ -459,7 +458,7 @@ namespace Ryujinx.UI (Toplevel as MainWindow)?.ActivatePauseMenu(); - while (_isActive) + while (Device.IsActive) { if (_isStopped) { @@ -519,7 +518,7 @@ namespace Ryujinx.UI { _chrono.Restart(); - _isActive = true; + Device.IsActive = true; Gtk.Window parent = Toplevel as Gtk.Window; @@ -573,9 +572,9 @@ namespace Ryujinx.UI _isStopped = true; - if (_isActive) + if (Device.IsActive) { - _isActive = false; + Device.IsActive = false; _exitEvent.WaitOne(); _exitEvent.Dispose(); @@ -584,7 +583,7 @@ namespace Ryujinx.UI private void NvidiaStutterWorkaround() { - while (_isActive) + while (Device.IsActive) { // When NVIDIA Threaded Optimization is on, the driver will snapshot all threads in the system whenever the application creates any new ones. // The ThreadPool has something called a "GateThread" which terminates itself after some inactivity. @@ -603,7 +602,7 @@ namespace Ryujinx.UI public void MainLoop() { - while (_isActive) + while (Device.IsActive) { UpdateFrame(); @@ -616,7 +615,7 @@ namespace Ryujinx.UI private bool UpdateFrame() { - if (!_isActive) + if (!Device.IsActive) { return true; } diff --git a/src/Ryujinx.HLE/Debugger/Debugger.cs b/src/Ryujinx.HLE/Debugger/Debugger.cs index abf6a19be..4870b5661 100644 --- a/src/Ryujinx.HLE/Debugger/Debugger.cs +++ b/src/Ryujinx.HLE/Debugger/Debugger.cs @@ -218,6 +218,8 @@ namespace Ryujinx.HLE.Debugger } case 'k': Logger.Notice.Print(LogClass.GdbStub, "Kill request received"); + Device.IsActive = false; + Device.ExitStatus.WaitOne(); Reply(""); break; case 'm': diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs index adef6ed78..2c6d77c15 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs @@ -311,7 +311,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading { KernelContext.CriticalSection.Enter(); - if (Owner != null && Owner.PinnedThreads[KernelStatic.GetCurrentThread().CurrentCore] == this) + KThread currentThread = KernelStatic.GetCurrentThread(); + + if (Owner != null && currentThread != null && Owner.PinnedThreads[currentThread.CurrentCore] == this) { Owner.UnpinThread(this); } @@ -366,7 +368,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading { ThreadSchedState state = PrepareForTermination(); - if (state != ThreadSchedState.TerminationPending) + if (KernelStatic.GetCurrentThread() == this && state != ThreadSchedState.TerminationPending) { KernelContext.Synchronization.WaitFor(new KSynchronizationObject[] { this }, -1, out _); } diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index fc7809ff4..b2ec6f964 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -10,6 +10,7 @@ using Ryujinx.HLE.Loaders.Processes; using Ryujinx.HLE.UI; using Ryujinx.Memory; using System; +using System.Threading; namespace Ryujinx.HLE { @@ -27,11 +28,14 @@ namespace Ryujinx.HLE public TamperMachine TamperMachine { get; } public IHostUIHandler UIHandler { get; } public Debugger.Debugger Debugger { get; } + public ManualResetEvent ExitStatus { get; } public bool EnableDeviceVsync { get; set; } = true; public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable; + public bool IsActive { get; set; } = true; + public Switch(HLEConfiguration configuration) { ArgumentNullException.ThrowIfNull(configuration.GpuRenderer); @@ -56,6 +60,7 @@ namespace Ryujinx.HLE Hid = new Hid(this, System.HidStorage); Processes = new ProcessLoader(this); TamperMachine = new TamperMachine(); + ExitStatus = new ManualResetEvent(false); System.InitializeServices(); System.State.SetLanguage(Configuration.SystemLanguage); @@ -157,6 +162,7 @@ namespace Ryujinx.HLE FileSystem.Dispose(); Memory.Dispose(); Debugger.Dispose(); + ExitStatus.Set(); } } } diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index 65ef63926..2e847c620 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -104,7 +104,6 @@ namespace Ryujinx.Ava CursorStates.CursorIsVisible : CursorStates.CursorIsHidden; private bool _isStopped; - private bool _isActive; private bool _renderingStarted; private readonly ManualResetEvent _gpuDoneEvent; @@ -427,8 +426,6 @@ namespace Ryujinx.Ava RendererHost.BoundsChanged += Window_BoundsChanged; - _isActive = true; - _renderingThread.Start(); _viewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value; @@ -497,7 +494,7 @@ namespace Ryujinx.Ava public void Stop() { - _isActive = false; + Device.IsActive = false; } private void Exit() @@ -510,14 +507,14 @@ namespace Ryujinx.Ava } _isStopped = true; - _isActive = false; + Device.IsActive = false; } public void DisposeContext() { Dispose(); - _isActive = false; + Device.IsActive = false; // NOTE: The render loop is allowed to stay alive until the renderer itself is disposed, as it may handle resource dispose. // We only need to wait for all commands submitted during the main gpu loop to be processed. @@ -950,7 +947,7 @@ namespace Ryujinx.Ava private void MainLoop() { - while (_isActive) + while (Device.IsActive) { UpdateFrame(); @@ -1001,7 +998,7 @@ namespace Ryujinx.Ava _renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync); - while (_isActive) + while (Device.IsActive) { _ticks += _chrono.ElapsedTicks; @@ -1100,7 +1097,7 @@ namespace Ryujinx.Ava private bool UpdateFrame() { - if (!_isActive) + if (!Device.IsActive) { return false; }