From 00ce9eea620652b97b4d3e8cd9218c6fccff8b1c Mon Sep 17 00:00:00 2001
From: Mary <me@thog.eu>
Date: Tue, 29 Jun 2021 19:37:13 +0200
Subject: Fix disposing of IPC sessions server at emulation stop (#2334)

---
 Ryujinx.HLE/HOS/Services/ServerBase.cs | 41 ++++++++++++++++++++++++++++------
 1 file changed, 34 insertions(+), 7 deletions(-)

(limited to 'Ryujinx.HLE/HOS/Services/ServerBase.cs')

diff --git a/Ryujinx.HLE/HOS/Services/ServerBase.cs b/Ryujinx.HLE/HOS/Services/ServerBase.cs
index c9d009a9..695394a5 100644
--- a/Ryujinx.HLE/HOS/Services/ServerBase.cs
+++ b/Ryujinx.HLE/HOS/Services/ServerBase.cs
@@ -4,6 +4,7 @@ using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Services.Sm;
 using System;
 using System.Buffers.Binary;
 using System.Collections.Generic;
@@ -12,7 +13,7 @@ using System.Threading;
 
 namespace Ryujinx.HLE.HOS.Services
 {
-    class ServerBase
+    class ServerBase : IDisposable
     {
         // Must be the maximum value used by services (highest one know is the one used by nvservices = 0x8000).
         // Having a size that is too low will cause failures as data copy will fail if the receiving buffer is
@@ -67,6 +68,9 @@ namespace Ryujinx.HLE.HOS.Services
 
         public void AddSessionObj(KServerSession serverSession, IpcService obj)
         {
+            // Ensure that the sever loop is running.
+            InitDone.WaitOne();
+
             _selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle);
             AddSessionObj(serverSessionHandle, obj);
         }
@@ -86,14 +90,10 @@ namespace Ryujinx.HLE.HOS.Services
                 _context.Syscall.ManageNamedPort("sm:", 50, out int serverPortHandle);
 
                 AddPort(serverPortHandle, SmObjectFactory);
-
-                InitDone.Set();
-            }
-            else
-            {
-                InitDone.Dispose();
             }
 
+            InitDone.Set();
+
             KThread thread = KernelStatic.GetCurrentThread();
             ulong messagePtr = thread.TlsAddress;
             _context.Syscall.SetHeapSize(0x200000, out ulong heapAddr);
@@ -153,6 +153,8 @@ namespace Ryujinx.HLE.HOS.Services
                     _selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48));
                 }
             }
+
+            Dispose();
         }
 
         private bool Process(int serverSessionHandle, ulong recvListAddr)
@@ -349,5 +351,30 @@ namespace Ryujinx.HLE.HOS.Services
 
             return response;
         }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                foreach (IpcService service in _sessions.Values)
+                {
+                    if (service is IDisposable disposableObj)
+                    {
+                        disposableObj.Dispose();
+                    }
+
+                    service.DestroyAtExit();
+                }
+
+                _sessions.Clear();
+
+                InitDone.Dispose();
+            }
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2