Эх сурвалжийг харах

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
Thog 6 жил өмнө
parent
commit
a906f2071c

+ 1 - 0
Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs

@@ -101,6 +101,7 @@ namespace Ryujinx.Audio
             }
 
             _tracks.Clear();
+            _context.Dispose();
         }
 
         /// <summary>

+ 4 - 1
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<ApplicationControlProperty> 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);

+ 5 - 0
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();
+        }
     }
 }

+ 2 - 0
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();
         }
 

+ 1 - 1
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();

+ 14 - 4
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);
+        }
     }
 }

+ 13 - 4
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);
         }