Kill command - stop emulation

This commit is contained in:
svc64 2023-11-17 19:15:37 +02:00
parent 38c15faacf
commit 055ac70eaa
6 changed files with 29 additions and 24 deletions

View file

@ -1076,9 +1076,11 @@ namespace Ryujinx.UI
RendererWidget.WaitEvent.WaitOne(); RendererWidget.WaitEvent.WaitOne();
RendererWidget.Start(); RendererWidget.Start();
_pauseEmulation.Sensitive = false;
_resumeEmulation.Sensitive = false;
UpdateMenuItem.Sensitive = true;
_emulationContext.Dispose(); _emulationContext.Dispose();
_deviceExitStatus.Set();
// NOTE: Everything that is here will not be executed when you close the UI. // NOTE: Everything that is here will not be executed when you close the UI.
Application.Invoke(delegate Application.Invoke(delegate
@ -1173,7 +1175,7 @@ namespace Ryujinx.UI
RendererWidget.Exit(); RendererWidget.Exit();
// Wait for the other thread to dispose the HLE context before exiting. // Wait for the other thread to dispose the HLE context before exiting.
_deviceExitStatus.WaitOne(); _emulationContext.ExitStatus.WaitOne();
RendererWidget.Dispose(); RendererWidget.Dispose();
} }
} }
@ -1511,9 +1513,6 @@ namespace Ryujinx.UI
UpdateGameMetadata(_emulationContext.Processes.ActiveApplication.ProgramIdText); UpdateGameMetadata(_emulationContext.Processes.ActiveApplication.ProgramIdText);
} }
_pauseEmulation.Sensitive = false;
_resumeEmulation.Sensitive = false;
UpdateMenuItem.Sensitive = true;
RendererWidget?.Exit(); RendererWidget?.Exit();
} }

View file

@ -49,7 +49,6 @@ namespace Ryujinx.UI
public static event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent; public static event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
private bool _isActive;
private bool _isStopped; private bool _isStopped;
private bool _toggleFullscreen; private bool _toggleFullscreen;
@ -459,7 +458,7 @@ namespace Ryujinx.UI
(Toplevel as MainWindow)?.ActivatePauseMenu(); (Toplevel as MainWindow)?.ActivatePauseMenu();
while (_isActive) while (Device.IsActive)
{ {
if (_isStopped) if (_isStopped)
{ {
@ -519,7 +518,7 @@ namespace Ryujinx.UI
{ {
_chrono.Restart(); _chrono.Restart();
_isActive = true; Device.IsActive = true;
Gtk.Window parent = Toplevel as Gtk.Window; Gtk.Window parent = Toplevel as Gtk.Window;
@ -573,9 +572,9 @@ namespace Ryujinx.UI
_isStopped = true; _isStopped = true;
if (_isActive) if (Device.IsActive)
{ {
_isActive = false; Device.IsActive = false;
_exitEvent.WaitOne(); _exitEvent.WaitOne();
_exitEvent.Dispose(); _exitEvent.Dispose();
@ -584,7 +583,7 @@ namespace Ryujinx.UI
private void NvidiaStutterWorkaround() 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. // 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. // The ThreadPool has something called a "GateThread" which terminates itself after some inactivity.
@ -603,7 +602,7 @@ namespace Ryujinx.UI
public void MainLoop() public void MainLoop()
{ {
while (_isActive) while (Device.IsActive)
{ {
UpdateFrame(); UpdateFrame();
@ -616,7 +615,7 @@ namespace Ryujinx.UI
private bool UpdateFrame() private bool UpdateFrame()
{ {
if (!_isActive) if (!Device.IsActive)
{ {
return true; return true;
} }

View file

@ -218,6 +218,8 @@ namespace Ryujinx.HLE.Debugger
} }
case 'k': case 'k':
Logger.Notice.Print(LogClass.GdbStub, "Kill request received"); Logger.Notice.Print(LogClass.GdbStub, "Kill request received");
Device.IsActive = false;
Device.ExitStatus.WaitOne();
Reply(""); Reply("");
break; break;
case 'm': case 'm':

View file

@ -311,7 +311,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
KernelContext.CriticalSection.Enter(); 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); Owner.UnpinThread(this);
} }
@ -366,7 +368,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
ThreadSchedState state = PrepareForTermination(); ThreadSchedState state = PrepareForTermination();
if (state != ThreadSchedState.TerminationPending) if (KernelStatic.GetCurrentThread() == this && state != ThreadSchedState.TerminationPending)
{ {
KernelContext.Synchronization.WaitFor(new KSynchronizationObject[] { this }, -1, out _); KernelContext.Synchronization.WaitFor(new KSynchronizationObject[] { this }, -1, out _);
} }

View file

@ -10,6 +10,7 @@ using Ryujinx.HLE.Loaders.Processes;
using Ryujinx.HLE.UI; using Ryujinx.HLE.UI;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
using System.Threading;
namespace Ryujinx.HLE namespace Ryujinx.HLE
{ {
@ -27,11 +28,14 @@ namespace Ryujinx.HLE
public TamperMachine TamperMachine { get; } public TamperMachine TamperMachine { get; }
public IHostUIHandler UIHandler { get; } public IHostUIHandler UIHandler { get; }
public Debugger.Debugger Debugger { get; } public Debugger.Debugger Debugger { get; }
public ManualResetEvent ExitStatus { get; }
public bool EnableDeviceVsync { get; set; } = true; public bool EnableDeviceVsync { get; set; } = true;
public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable; public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable;
public bool IsActive { get; set; } = true;
public Switch(HLEConfiguration configuration) public Switch(HLEConfiguration configuration)
{ {
ArgumentNullException.ThrowIfNull(configuration.GpuRenderer); ArgumentNullException.ThrowIfNull(configuration.GpuRenderer);
@ -56,6 +60,7 @@ namespace Ryujinx.HLE
Hid = new Hid(this, System.HidStorage); Hid = new Hid(this, System.HidStorage);
Processes = new ProcessLoader(this); Processes = new ProcessLoader(this);
TamperMachine = new TamperMachine(); TamperMachine = new TamperMachine();
ExitStatus = new ManualResetEvent(false);
System.InitializeServices(); System.InitializeServices();
System.State.SetLanguage(Configuration.SystemLanguage); System.State.SetLanguage(Configuration.SystemLanguage);
@ -157,6 +162,7 @@ namespace Ryujinx.HLE
FileSystem.Dispose(); FileSystem.Dispose();
Memory.Dispose(); Memory.Dispose();
Debugger.Dispose(); Debugger.Dispose();
ExitStatus.Set();
} }
} }
} }

View file

@ -104,7 +104,6 @@ namespace Ryujinx.Ava
CursorStates.CursorIsVisible : CursorStates.CursorIsHidden; CursorStates.CursorIsVisible : CursorStates.CursorIsHidden;
private bool _isStopped; private bool _isStopped;
private bool _isActive;
private bool _renderingStarted; private bool _renderingStarted;
private readonly ManualResetEvent _gpuDoneEvent; private readonly ManualResetEvent _gpuDoneEvent;
@ -427,8 +426,6 @@ namespace Ryujinx.Ava
RendererHost.BoundsChanged += Window_BoundsChanged; RendererHost.BoundsChanged += Window_BoundsChanged;
_isActive = true;
_renderingThread.Start(); _renderingThread.Start();
_viewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value; _viewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value;
@ -497,7 +494,7 @@ namespace Ryujinx.Ava
public void Stop() public void Stop()
{ {
_isActive = false; Device.IsActive = false;
} }
private void Exit() private void Exit()
@ -510,14 +507,14 @@ namespace Ryujinx.Ava
} }
_isStopped = true; _isStopped = true;
_isActive = false; Device.IsActive = false;
} }
public void DisposeContext() public void DisposeContext()
{ {
Dispose(); 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. // 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. // 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() private void MainLoop()
{ {
while (_isActive) while (Device.IsActive)
{ {
UpdateFrame(); UpdateFrame();
@ -1001,7 +998,7 @@ namespace Ryujinx.Ava
_renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync); _renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync);
while (_isActive) while (Device.IsActive)
{ {
_ticks += _chrono.ElapsedTicks; _ticks += _chrono.ElapsedTicks;
@ -1100,7 +1097,7 @@ namespace Ryujinx.Ava
private bool UpdateFrame() private bool UpdateFrame()
{ {
if (!_isActive) if (!Device.IsActive)
{ {
return false; return false;
} }