aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMary <me@thog.eu>2021-06-29 19:37:13 +0200
committerGitHub <noreply@github.com>2021-06-29 19:37:13 +0200
commit00ce9eea620652b97b4d3e8cd9218c6fccff8b1c (patch)
treef488b1b378a8ecbeaf54d5a7916062784a5588dc
parentfbb4019ed5c12c4a888c7b09db648ac595366896 (diff)
Fix disposing of IPC sessions server at emulation stop (#2334)
-rw-r--r--Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceDriver.cs23
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs26
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs6
-rw-r--r--Ryujinx.Audio/Input/AudioInputManager.cs25
-rw-r--r--Ryujinx.Audio/Input/AudioInputSystem.cs13
-rw-r--r--Ryujinx.Audio/Output/AudioOutputManager.cs25
-rw-r--r--Ryujinx.Audio/Output/AudioOutputSystem.cs11
-rw-r--r--Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs7
-rw-r--r--Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs10
-rw-r--r--Ryujinx.HLE/HOS/Horizon.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs27
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/DisposableIpcService.cs20
-rw-r--r--Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/IpcService.cs13
-rw-r--r--Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs15
-rw-r--r--Ryujinx.HLE/HOS/Services/ServerBase.cs41
-rw-r--r--Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs7
-rw-r--r--Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs13
28 files changed, 283 insertions, 122 deletions
diff --git a/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceDriver.cs b/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceDriver.cs
index 387ae772..721e96c6 100644
--- a/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceDriver.cs
+++ b/Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceDriver.cs
@@ -133,19 +133,28 @@ namespace Ryujinx.Audio.Backends.OpenAL
{
if (disposing)
{
- lock (_lock)
- {
- _stillRunning = false;
- _updaterThread.Join();
+ _stillRunning = false;
- // Loop against all sessions to dispose them (they will unregister themself)
- while (_sessions.Count > 0)
+ int sessionCount = 0;
+
+ // NOTE: This is done in a way to avoid possible situations when the OpenALHardwareDeviceSession is already being dispose in another thread but doesn't hold the lock and tries to Unregister.
+ do
+ {
+ lock (_lock)
{
- OpenALHardwareDeviceSession session = _sessions[0];
+ if (_sessions.Count == 0)
+ {
+ break;
+ }
+
+ OpenALHardwareDeviceSession session = _sessions[_sessions.Count - 1];
session.Dispose();
+
+ sessionCount = _sessions.Count;
}
}
+ while (sessionCount > 0);
ALC.DestroyContext(_context);
ALC.CloseDevice(_device);
diff --git a/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs b/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs
index 00977fcb..b9b549e6 100644
--- a/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs
+++ b/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs
@@ -18,6 +18,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
private SoundIODevice _audioDevice;
private ManualResetEvent _updateRequiredEvent;
private List<SoundIoHardwareDeviceSession> _sessions;
+ private int _disposeState;
public SoundIoHardwareDeviceDriver()
{
@@ -208,19 +209,36 @@ namespace Ryujinx.Audio.Backends.SoundIo
public void Dispose()
{
- Dispose(true);
+ if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
+ {
+ Dispose(true);
+ }
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
- while (_sessions.Count > 0)
+ int sessionCount = 0;
+
+ // NOTE: This is done in a way to avoid possible situations when the SoundIoHardwareDeviceSession is already being dispose in another thread but doesn't hold the lock and tries to Unregister.
+ do
{
- SoundIoHardwareDeviceSession session = _sessions[_sessions.Count - 1];
+ lock (_lock)
+ {
+ if (_sessions.Count == 0)
+ {
+ break;
+ }
+
+ SoundIoHardwareDeviceSession session = _sessions[_sessions.Count - 1];
+
+ session.Dispose();
- session.Dispose();
+ sessionCount = _sessions.Count;
+ }
}
+ while (sessionCount > 0);
_audioContext.Disconnect();
_audioContext.Dispose();
diff --git a/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs b/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs
index 925a1cb4..884e75ed 100644
--- a/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs
+++ b/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs
@@ -17,6 +17,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
private DynamicRingBuffer _ringBuffer;
private ulong _playedSampleCount;
private ManualResetEvent _updateRequiredEvent;
+ private int _disposeState;
public SoundIoHardwareDeviceSession(SoundIoHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
{
@@ -435,7 +436,10 @@ namespace Ryujinx.Audio.Backends.SoundIo
public override void Dispose()
{
- Dispose(true);
+ if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
+ {
+ Dispose(true);
+ }
}
}
}
diff --git a/Ryujinx.Audio/Input/AudioInputManager.cs b/Ryujinx.Audio/Input/AudioInputManager.cs
index e098ae9e..5c1f01db 100644
--- a/Ryujinx.Audio/Input/AudioInputManager.cs
+++ b/Ryujinx.Audio/Input/AudioInputManager.cs
@@ -21,6 +21,8 @@ using Ryujinx.Common.Logging;
using Ryujinx.Memory;
using System;
using System.Diagnostics;
+using System.Linq;
+using System.Threading;
namespace Ryujinx.Audio.Input
{
@@ -62,6 +64,11 @@ namespace Ryujinx.Audio.Input
private int _activeSessionCount;
/// <summary>
+ /// The dispose state.
+ /// </summary>
+ private int _disposeState;
+
+ /// <summary>
/// Create a new <see cref="AudioInputManager"/>.
/// </summary>
public AudioInputManager()
@@ -248,14 +255,28 @@ namespace Ryujinx.Audio.Input
public void Dispose()
{
- Dispose(true);
+ if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
+ {
+ Dispose(true);
+ }
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
- // Nothing to do here.
+ // Clone the sessions array to dispose them outside the lock.
+ AudioInputSystem[] sessions;
+
+ lock (_sessionLock)
+ {
+ sessions = _sessions.ToArray();
+ }
+
+ foreach (AudioInputSystem input in sessions)
+ {
+ input?.Dispose();
+ }
}
}
}
diff --git a/Ryujinx.Audio/Input/AudioInputSystem.cs b/Ryujinx.Audio/Input/AudioInputSystem.cs
index 8064a947..b3fd91e7 100644
--- a/Ryujinx.Audio/Input/AudioInputSystem.cs
+++ b/Ryujinx.Audio/Input/AudioInputSystem.cs
@@ -18,6 +18,7 @@
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using System;
+using System.Threading;
namespace Ryujinx.Audio.Input
{
@@ -62,11 +63,16 @@ namespace Ryujinx.Audio.Input
private AudioInputManager _manager;
/// <summary>
- /// THe lock of the parent.
+ /// The lock of the parent.
/// </summary>
private object _parentLock;
/// <summary>
+ /// The dispose state.
+ /// </summary>
+ private int _disposeState;
+
+ /// <summary>
/// Create a new <see cref="AudioInputSystem"/>.
/// </summary>
/// <param name="manager">The manager instance</param>
@@ -384,7 +390,10 @@ namespace Ryujinx.Audio.Input
public void Dispose()
{
- Dispose(true);
+ if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
+ {
+ Dispose(true);
+ }
}
protected virtual void Dispose(bool disposing)
diff --git a/Ryujinx.Audio/Output/AudioOutputManager.cs b/Ryujinx.Audio/Output/AudioOutputManager.cs
index baa84997..852632fa 100644
--- a/Ryujinx.Audio/Output/AudioOutputManager.cs
+++ b/Ryujinx.Audio/Output/AudioOutputManager.cs
@@ -21,6 +21,8 @@ using Ryujinx.Common.Logging;
using Ryujinx.Memory;
using System;
using System.Diagnostics;
+using System.Linq;
+using System.Threading;
namespace Ryujinx.Audio.Output
{
@@ -62,6 +64,11 @@ namespace Ryujinx.Audio.Output
private int _activeSessionCount;
/// <summary>
+ /// The dispose state.
+ /// </summary>
+ private int _disposeState;
+
+ /// <summary>
/// Create a new <see cref="AudioOutputManager"/>.
/// </summary>
public AudioOutputManager()
@@ -242,14 +249,28 @@ namespace Ryujinx.Audio.Output
public void Dispose()
{
- Dispose(true);
+ if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
+ {
+ Dispose(true);
+ }
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
- // Nothing to do here.
+ // Clone the sessions array to dispose them outside the lock.
+ AudioOutputSystem[] sessions;
+
+ lock (_sessionLock)
+ {
+ sessions = _sessions.ToArray();
+ }
+
+ foreach (AudioOutputSystem output in sessions)
+ {
+ output?.Dispose();
+ }
}
}
}
diff --git a/Ryujinx.Audio/Output/AudioOutputSystem.cs b/Ryujinx.Audio/Output/AudioOutputSystem.cs
index f5db9d7a..d32d417a 100644
--- a/Ryujinx.Audio/Output/AudioOutputSystem.cs
+++ b/Ryujinx.Audio/Output/AudioOutputSystem.cs
@@ -18,6 +18,7 @@
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using System;
+using System.Threading;
namespace Ryujinx.Audio.Output
{
@@ -67,6 +68,11 @@ namespace Ryujinx.Audio.Output
private object _parentLock;
/// <summary>
+ /// The dispose state.
+ /// </summary>
+ private int _disposeState;
+
+ /// <summary>
/// Create a new <see cref="AudioOutputSystem"/>.
/// </summary>
/// <param name="manager">The manager instance</param>
@@ -357,7 +363,10 @@ namespace Ryujinx.Audio.Output
public void Dispose()
{
- Dispose(true);
+ if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
+ {
+ Dispose(true);
+ }
}
protected virtual void Dispose(bool disposing)
diff --git a/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs b/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs
index 943a2d78..6aed3c5d 100644
--- a/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs
+++ b/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs
@@ -94,6 +94,8 @@ namespace Ryujinx.Audio.Renderer.Server
private AudioRendererManager _manager;
+ private int _disposeState;
+
public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent)
{
_manager = manager;
@@ -811,7 +813,10 @@ namespace Ryujinx.Audio.Renderer.Server
public void Dispose()
{
- Dispose(true);
+ if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
+ {
+ Dispose(true);
+ }
}
protected virtual void Dispose(bool disposing)
diff --git a/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs b/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs
index 004ac656..71d0f318 100644
--- a/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs
+++ b/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs
@@ -83,6 +83,11 @@ namespace Ryujinx.Audio.Renderer.Server
public AudioProcessor Processor { get; }
/// <summary>
+ /// The dispose state.
+ /// </summary>
+ private int _disposeState;
+
+ /// <summary>
/// Create a new <see cref="AudioRendererManager"/>.
/// </summary>
public AudioRendererManager()
@@ -313,7 +318,10 @@ namespace Ryujinx.Audio.Renderer.Server
public void Dispose()
{
- Dispose(true);
+ if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
+ {
+ Dispose(true);
+ }
}
protected virtual void Dispose(bool disposing)
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index a4ed7c37..916ed797 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -70,6 +70,7 @@ namespace Ryujinx.HLE.HOS
internal List<NfpDevice> NfpDevices { get; private set; }
+ internal ServerBase SmServer { get; private set; }
internal ServerBase BsdServer { get; private set; }
internal ServerBase AudRenServer { get; private set; }
internal ServerBase AudOutServer { get; private set; }
@@ -284,13 +285,11 @@ namespace Ryujinx.HLE.HOS
public void InitializeServices()
{
- IUserInterface sm = new IUserInterface(KernelContext);
- sm.TrySetServer(new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext)));
+ SmServer = new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext));
// Wait until SM server thread is done with initialization,
// only then doing connections to SM is safe.
- sm.Server.InitDone.WaitOne();
- sm.Server.InitDone.Dispose();
+ SmServer.InitDone.WaitOne();
BsdServer = new ServerBase(KernelContext, "BsdServer");
AudRenServer = new ServerBase(KernelContext, "AudioRendererServer");
@@ -419,7 +418,7 @@ namespace Ryujinx.HLE.HOS
SurfaceFlinger.Dispose();
// Terminate HLE services (must be done after the application is already terminated,
- // otherwise the application will receive errors due to service termination.
+ // otherwise the application will receive errors due to service termination).
foreach (KProcess process in KernelContext.Processes.Values.Where(x => !x.Flags.HasFlag(ProcessCreationFlags.IsApplication)))
{
process.Terminate();
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
index 1377eac0..2deb830e 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
@@ -8,7 +8,7 @@ using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletCreator
{
- class ILibraryAppletAccessor : IpcService, IDisposable
+ class ILibraryAppletAccessor : DisposableIpcService
{
private KernelContext _kernelContext;
@@ -241,21 +241,24 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
return ResultCode.Success;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- if (_stateChangedEventHandle != 0)
+ if (isDisposing)
{
- _kernelContext.Syscall.CloseHandle(_stateChangedEventHandle);
- }
+ if (_stateChangedEventHandle != 0)
+ {
+ _kernelContext.Syscall.CloseHandle(_stateChangedEventHandle);
+ }
- if (_normalOutDataEventHandle != 0)
- {
- _kernelContext.Syscall.CloseHandle(_normalOutDataEventHandle);
- }
+ if (_normalOutDataEventHandle != 0)
+ {
+ _kernelContext.Syscall.CloseHandle(_normalOutDataEventHandle);
+ }
- if (_interactiveOutDataEventHandle != 0)
- {
- _kernelContext.Syscall.CloseHandle(_interactiveOutDataEventHandle);
+ if (_interactiveOutDataEventHandle != 0)
+ {
+ _kernelContext.Syscall.CloseHandle(_interactiveOutDataEventHandle);
+ }
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs
index b45a4d2c..f9a9447f 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs
@@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Audio.AudioIn
{
- class AudioInServer : IpcService, IDisposable
+ class AudioInServer : DisposableIpcService
{
private IAudioIn _impl;
@@ -193,14 +193,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioIn
return ResultCode.Success;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- Dispose(true);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
+ if (isDisposing)
{
_impl.Dispose();
}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs
index b7515e0f..aff08811 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs
@@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut
{
- class AudioOutServer : IpcService, IDisposable
+ class AudioOutServer : DisposableIpcService
{
private IAudioOut _impl;
@@ -174,14 +174,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut
return ResultCode.Success;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- Dispose(true);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
+ if (isDisposing)
{
_impl.Dispose();
}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
index bb51b506..bd5030f3 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
@@ -7,7 +7,7 @@ using System.Buffers;
namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
{
- class AudioRendererServer : IpcService, IDisposable
+ class AudioRendererServer : DisposableIpcService
{
private IAudioRenderer _impl;
@@ -172,14 +172,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
return result;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- Dispose(true);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
+ if (isDisposing)
{
_impl.Dispose();
}
diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs
index 51d8f66c..46c2c09c 100644
--- a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs
+++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs
@@ -1,12 +1,11 @@
using LibHac;
using LibHac.Bcat;
using Ryujinx.Common;
-using System;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{
- class IDeliveryCacheDirectoryService : IpcService, IDisposable
+ class IDeliveryCacheDirectoryService : DisposableIpcService
{
private LibHac.Bcat.Detail.Ipc.IDeliveryCacheDirectoryService _base;
@@ -55,9 +54,12 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
return (ResultCode)result.Value;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- _base?.Dispose();
+ if (isDisposing)
+ {
+ _base?.Dispose();
+ }
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs
index 9354b60e..55c89a3e 100644
--- a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs
+++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs
@@ -1,11 +1,10 @@
using LibHac;
using LibHac.Bcat;
using Ryujinx.Common;
-using System;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{
- class IDeliveryCacheFileService : IpcService, IDisposable
+ class IDeliveryCacheFileService : DisposableIpcService
{
private LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService _base;
@@ -68,9 +67,12 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
return (ResultCode)result.Value;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- _base?.Dispose();
+ if (isDisposing)
+ {
+ _base?.Dispose();
+ }
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs
index cac5f170..0d2f2521 100644
--- a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs
+++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs
@@ -1,11 +1,10 @@
using LibHac;
using LibHac.Bcat;
-using System;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{
- class IDeliveryCacheStorageService : IpcService, IDisposable
+ class IDeliveryCacheStorageService : DisposableIpcService
{
private LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService _base;
@@ -60,9 +59,12 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
return (ResultCode)result.Value;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- _base?.Dispose();
+ if (isDisposing)
+ {
+ _base?.Dispose();
+ }
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/DisposableIpcService.cs b/Ryujinx.HLE/HOS/Services/DisposableIpcService.cs
new file mode 100644
index 00000000..7aecdfd1
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/DisposableIpcService.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Threading;
+
+namespace Ryujinx.HLE.HOS.Services
+{
+ abstract class DisposableIpcService : IpcService, IDisposable
+ {
+ private int _disposeState;
+
+ protected abstract void Dispose(bool isDisposing);
+
+ public void Dispose()
+ {
+ if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
+ {
+ Dispose(true);
+ }
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs
index 700d4ab4..f5614ddd 100644
--- a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs
+++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs
@@ -9,7 +9,7 @@ using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
{
- class INotificationService : IpcService, IDisposable
+ class INotificationService : DisposableIpcService
{
private readonly UserId _userId;
private readonly FriendServicePermissionLevel _permissionLevel;
@@ -167,9 +167,12 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
}
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- NotificationEventHandler.Instance.UnregisterNotificationService(this);
+ if (isDisposing)
+ {
+ NotificationEventHandler.Instance.UnregisterNotificationService(this);
+ }
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs
index 681b6c17..cf1611e7 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs
@@ -1,10 +1,9 @@
using LibHac;
using LibHac.Fs;
-using System;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{
- class IFile : IpcService, IDisposable
+ class IFile : DisposableIpcService
{
private LibHac.Fs.Fsa.IFile _baseFile;
@@ -82,14 +81,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
return (ResultCode)result.Value;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- Dispose(true);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
+ if (isDisposing)
{
_baseFile?.Dispose();
}
diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs
index 89955634..62a3c62a 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs
@@ -1,10 +1,9 @@
using LibHac;
using Ryujinx.HLE.HOS.Ipc;
-using System;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{
- class IStorage : IpcService, IDisposable
+ class IStorage : DisposableIpcService
{
private LibHac.Fs.IStorage _baseStorage;
@@ -53,14 +52,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
return (ResultCode)result.Value;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- Dispose(true);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
+ if (isDisposing)
{
_baseStorage?.Dispose();
}
diff --git a/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs b/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs
index d6449a2d..bc4a2eb9 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs
@@ -3,7 +3,7 @@ using LibHac;
namespace Ryujinx.HLE.HOS.Services.Fs
{
- class ISaveDataInfoReader : IpcService, IDisposable
+ class ISaveDataInfoReader : DisposableIpcService
{
private ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> _baseReader;
@@ -29,9 +29,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs
return (ResultCode)result.Value;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- _baseReader.Dispose();
+ if (isDisposing)
+ {
+ _baseReader?.Dispose();
+ }
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/IpcService.cs b/Ryujinx.HLE/HOS/Services/IpcService.cs
index e9582c26..e3306071 100644
--- a/Ryujinx.HLE/HOS/Services/IpcService.cs
+++ b/Ryujinx.HLE/HOS/Services/IpcService.cs
@@ -265,5 +265,18 @@ namespace Ryujinx.HLE.HOS.Services
{
_parent = parent._parent;
}
+
+ public virtual void DestroyAtExit()
+ {
+ foreach (object domainObject in _domainObjects.Values)
+ {
+ if (domainObject != this && domainObject is IDisposable disposableObj)
+ {
+ disposableObj.Dispose();
+ }
+ }
+
+ _domainObjects.Clear();
+ }
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs
index e650879b..2296838e 100644
--- a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs
+++ b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs
@@ -10,7 +10,7 @@ using System.Text;
namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
{
- class IGeneralService : IpcService, IDisposable
+ class IGeneralService : DisposableIpcService
{
private GeneralServiceDetail _generalServiceDetail;
@@ -197,9 +197,12 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
return (targetProperties, targetAddressInfo);
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- GeneralServiceManager.Remove(_generalServiceDetail.ClientId);
+ if (isDisposing)
+ {
+ GeneralServiceManager.Remove(_generalServiceDetail.ClientId);
+ }
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs b/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
index ff5db94f..aa17f6ac 100644
--- a/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
@@ -16,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
{
[Service("ldr:ro")]
[Service("ro:1")] // 7.0.0+
- class IRoInterface : IpcService, IDisposable
+ class IRoInterface : DisposableIpcService
{
private const int MaxNrr = 0x40;
private const int MaxNro = 0x40;
@@ -571,14 +571,17 @@ namespace Ryujinx.HLE.HOS.Services.Ro
return ResultCode.Success;
}
- public void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- foreach (NroInfo info in _nroInfos)
+ if (isDisposing)
{
- UnmapNroFromInfo(info);
- }
+ foreach (NroInfo info in _nroInfos)
+ {
+ UnmapNroFromInfo(info);
+ }
- _nroInfos.Clear();
+ _nroInfos.Clear();
+ }
}
}
} \ No newline at end of file
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
diff --git a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
index 8b1ec5b8..a5595e31 100644
--- a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
@@ -245,5 +245,12 @@ namespace Ryujinx.HLE.HOS.Services.Sm
return name;
}
+
+ public override void DestroyAtExit()
+ {
+ _commonServer.Dispose();
+
+ base.DestroyAtExit();
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs b/Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs
index 62e118d9..0f38e685 100644
--- a/Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs
@@ -4,10 +4,12 @@ using System.Security.Cryptography;
namespace Ryujinx.HLE.HOS.Services.Spl
{
[Service("csrng")]
- class IRandomInterface : IpcService, IDisposable
+ class IRandomInterface : DisposableIpcService
{
private RNGCryptoServiceProvider _rng;
+ private object _lock = new object();
+
public IRandomInterface(ServiceCtx context)
{
_rng = new RNGCryptoServiceProvider();
@@ -26,14 +28,9 @@ namespace Ryujinx.HLE.HOS.Services.Spl
return ResultCode.Success;
}
- public void Dispose()
- {
- Dispose(true);
- }
-
- protected virtual void Dispose(bool disposing)
+ protected override void Dispose(bool isDisposing)
{
- if (disposing)
+ if (isDisposing)
{
_rng.Dispose();
}