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

View file

@ -49,7 +49,6 @@ namespace Ryujinx.UI
public static event EventHandler<StatusUpdatedEventArgs> 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;
}

View file

@ -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':

View file

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

View file

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

View file

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