From a906f2071cbe4caf53c697bcb7dfa91e3e7dcfae Mon Sep 17 00:00:00 2001 From: Thog Date: Thu, 6 Feb 2020 12:38:24 +0100 Subject: [PATCH] Fix a crash when closing the main UI (#904) * Fix a crash when closing the main Ui Also make sure to dispose the OpenAL context to not leak memory when unloading the emulation context. * Improve keys and 'game already running' dialogs * Make sure to dispose the page table and ThreadContext Less memory leaks! * Fix tests * Address gdk's comments --- .../Renderers/OpenAL/OpenALAudioOut.cs | 1 + Ryujinx.HLE/HOS/Horizon.cs | 5 ++++- Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs | 5 +++++ Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs | 2 ++ Ryujinx/Program.cs | 2 +- Ryujinx/Ui/GtkDialog.cs | 18 ++++++++++++++---- Ryujinx/Ui/MainWindow.cs | 17 +++++++++++++---- 7 files changed, 40 insertions(+), 10 deletions(-) diff --git a/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs b/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs index 30b325a51..ea5ce6214 100644 --- a/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs +++ b/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs @@ -101,6 +101,7 @@ namespace Ryujinx.Audio } _tracks.Clear(); + _context.Dispose(); } /// diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index a2bff7f62..f8d2ed71b 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -107,6 +107,7 @@ namespace Ryujinx.HLE.HOS public Keyset KeySet => Device.FileSystem.KeySet; private bool _hasStarted; + private bool _isDisposed; public BlitStruct ControlData { get; set; } @@ -740,8 +741,10 @@ namespace Ryujinx.HLE.HOS protected virtual void Dispose(bool disposing) { - if (disposing) + if (!_isDisposed && disposing) { + _isDisposed = true; + KProcess terminationProcess = new KProcess(this); KThread terminationThread = new KThread(this); diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs index f987c83c0..7807ec5a6 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs @@ -1131,5 +1131,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { throw new UndefinedInstructionException(e.Address, e.OpCode); } + + protected override void Destroy() + { + CpuMemory.Dispose(); + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs index c4bd781d4..53eb5bdc9 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs @@ -1141,6 +1141,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading { Owner.Translator.Execute(Context, entrypoint); + Context.Dispose(); + ThreadExit(); } diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs index 5ce33a9dd..24fbb9b8b 100644 --- a/Ryujinx/Program.cs +++ b/Ryujinx/Program.cs @@ -51,7 +51,7 @@ namespace Ryujinx string userProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch", "prod.keys"); if (!File.Exists(appDataPath) && !File.Exists(userProfilePath) && !Migration.IsMigrationNeeded()) { - GtkDialog.CreateErrorDialog("Key file was not found. Please refer to `KEYS.md` for more info"); + GtkDialog.CreateWarningDialog("Key file was not found", "Please refer to `KEYS.md` for more info"); } MainWindow mainWindow = new MainWindow(); diff --git a/Ryujinx/Ui/GtkDialog.cs b/Ryujinx/Ui/GtkDialog.cs index 7f6be8dc7..b4e9fa1ca 100644 --- a/Ryujinx/Ui/GtkDialog.cs +++ b/Ryujinx/Ui/GtkDialog.cs @@ -5,19 +5,29 @@ namespace Ryujinx.Ui { internal class GtkDialog { - internal static void CreateErrorDialog(string errorMessage) + internal static void CreateDialog(string title, string text, string secondaryText) { MessageDialog errorDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, null) { - Title = "Ryujinx - Error", + Title = title, Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"), - Text = "Ryujinx has encountered an error", - SecondaryText = errorMessage, + Text = text, + SecondaryText = secondaryText, WindowPosition = WindowPosition.Center }; errorDialog.SetSizeRequest(100, 20); errorDialog.Run(); errorDialog.Dispose(); } + + internal static void CreateWarningDialog(string text, string secondaryText) + { + CreateDialog("Ryujinx - Warning", text, secondaryText); + } + + internal static void CreateErrorDialog(string errorMessage) + { + CreateDialog("Ryujinx - Error", "Ryujinx has encountered an error", errorMessage); + } } } diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index 84c736bef..734103fed 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -32,6 +32,8 @@ namespace Ryujinx.Ui private static GlScreen _screen; + private static AutoResetEvent _screenExitStatus = new AutoResetEvent(false); + private static ListStore _tableStore; private static bool _updatingGameTable; @@ -278,7 +280,7 @@ namespace Ryujinx.Ui { if (_gameLoaded) { - GtkDialog.CreateErrorDialog("A game has already been loaded. Please close the emulator and try again"); + GtkDialog.CreateDialog("Ryujinx", "A game has already been loaded", "Please close it first and try again."); } else { @@ -347,6 +349,8 @@ namespace Ryujinx.Ui _emulationContext = device; + _screenExitStatus.Reset(); + #if MACOS_BUILD CreateGameWindow(device); #else @@ -393,6 +397,8 @@ namespace Ryujinx.Ui DiscordIntegrationModule.SwitchToMainMenu(); + _screenExitStatus.Set(); + Application.Invoke(delegate { _stopEmulation.Sensitive = false; @@ -432,12 +438,17 @@ namespace Ryujinx.Ui if (device != null) { UpdateGameMetadata(device.System.TitleIdText); + + if (_screen != null) + { + _screen.Exit(); + _screenExitStatus.WaitOne(); + } } Dispose(); Profile.FinishProfiling(); - device?.Dispose(); DiscordIntegrationModule.Exit(); Logger.Shutdown(); Application.Quit(); @@ -584,13 +595,11 @@ namespace Ryujinx.Ui private void Exit_Pressed(object sender, EventArgs args) { - _screen?.Exit(); End(_emulationContext); } private void Window_Close(object sender, DeleteEventArgs args) { - _screen?.Exit(); End(_emulationContext); }