Fix disposing of IPC sessions server at emulation stop (#2334)

This commit is contained in:
Mary 2021-06-29 19:37:13 +02:00 committed by GitHub
parent fbb4019ed5
commit 00ce9eea62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 284 additions and 123 deletions

View file

@ -133,19 +133,28 @@ namespace Ryujinx.Audio.Backends.OpenAL
{ {
if (disposing) if (disposing)
{ {
lock (_lock) _stillRunning = false;
{
_stillRunning = false;
_updaterThread.Join();
// Loop against all sessions to dispose them (they will unregister themself) int sessionCount = 0;
while (_sessions.Count > 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(); session.Dispose();
sessionCount = _sessions.Count;
} }
} }
while (sessionCount > 0);
ALC.DestroyContext(_context); ALC.DestroyContext(_context);
ALC.CloseDevice(_device); ALC.CloseDevice(_device);

View file

@ -18,6 +18,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
private SoundIODevice _audioDevice; private SoundIODevice _audioDevice;
private ManualResetEvent _updateRequiredEvent; private ManualResetEvent _updateRequiredEvent;
private List<SoundIoHardwareDeviceSession> _sessions; private List<SoundIoHardwareDeviceSession> _sessions;
private int _disposeState;
public SoundIoHardwareDeviceDriver() public SoundIoHardwareDeviceDriver()
{ {
@ -208,19 +209,36 @@ namespace Ryujinx.Audio.Backends.SoundIo
public void Dispose() public void Dispose()
{ {
Dispose(true); if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
{
Dispose(true);
}
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (disposing) if (disposing)
{ {
while (_sessions.Count > 0) int sessionCount = 0;
{
SoundIoHardwareDeviceSession session = _sessions[_sessions.Count - 1];
session.Dispose(); // 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
{
lock (_lock)
{
if (_sessions.Count == 0)
{
break;
}
SoundIoHardwareDeviceSession session = _sessions[_sessions.Count - 1];
session.Dispose();
sessionCount = _sessions.Count;
}
} }
while (sessionCount > 0);
_audioContext.Disconnect(); _audioContext.Disconnect();
_audioContext.Dispose(); _audioContext.Dispose();

View file

@ -17,6 +17,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
private DynamicRingBuffer _ringBuffer; private DynamicRingBuffer _ringBuffer;
private ulong _playedSampleCount; private ulong _playedSampleCount;
private ManualResetEvent _updateRequiredEvent; private ManualResetEvent _updateRequiredEvent;
private int _disposeState;
public SoundIoHardwareDeviceSession(SoundIoHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) 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() public override void Dispose()
{ {
Dispose(true); if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
{
Dispose(true);
}
} }
} }
} }

View file

@ -21,6 +21,8 @@ using Ryujinx.Common.Logging;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace Ryujinx.Audio.Input namespace Ryujinx.Audio.Input
{ {
@ -61,6 +63,11 @@ namespace Ryujinx.Audio.Input
/// </summary> /// </summary>
private int _activeSessionCount; private int _activeSessionCount;
/// <summary>
/// The dispose state.
/// </summary>
private int _disposeState;
/// <summary> /// <summary>
/// Create a new <see cref="AudioInputManager"/>. /// Create a new <see cref="AudioInputManager"/>.
/// </summary> /// </summary>
@ -248,14 +255,28 @@ namespace Ryujinx.Audio.Input
public void Dispose() public void Dispose()
{ {
Dispose(true); if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
{
Dispose(true);
}
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (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();
}
} }
} }
} }

View file

@ -18,6 +18,7 @@
using Ryujinx.Audio.Common; using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration; using Ryujinx.Audio.Integration;
using System; using System;
using System.Threading;
namespace Ryujinx.Audio.Input namespace Ryujinx.Audio.Input
{ {
@ -62,10 +63,15 @@ namespace Ryujinx.Audio.Input
private AudioInputManager _manager; private AudioInputManager _manager;
/// <summary> /// <summary>
/// THe lock of the parent. /// The lock of the parent.
/// </summary> /// </summary>
private object _parentLock; private object _parentLock;
/// <summary>
/// The dispose state.
/// </summary>
private int _disposeState;
/// <summary> /// <summary>
/// Create a new <see cref="AudioInputSystem"/>. /// Create a new <see cref="AudioInputSystem"/>.
/// </summary> /// </summary>
@ -384,7 +390,10 @@ namespace Ryujinx.Audio.Input
public void Dispose() public void Dispose()
{ {
Dispose(true); if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
{
Dispose(true);
}
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)

View file

@ -21,6 +21,8 @@ using Ryujinx.Common.Logging;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace Ryujinx.Audio.Output namespace Ryujinx.Audio.Output
{ {
@ -61,6 +63,11 @@ namespace Ryujinx.Audio.Output
/// </summary> /// </summary>
private int _activeSessionCount; private int _activeSessionCount;
/// <summary>
/// The dispose state.
/// </summary>
private int _disposeState;
/// <summary> /// <summary>
/// Create a new <see cref="AudioOutputManager"/>. /// Create a new <see cref="AudioOutputManager"/>.
/// </summary> /// </summary>
@ -242,14 +249,28 @@ namespace Ryujinx.Audio.Output
public void Dispose() public void Dispose()
{ {
Dispose(true); if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
{
Dispose(true);
}
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (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();
}
} }
} }
} }

View file

@ -18,6 +18,7 @@
using Ryujinx.Audio.Common; using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration; using Ryujinx.Audio.Integration;
using System; using System;
using System.Threading;
namespace Ryujinx.Audio.Output namespace Ryujinx.Audio.Output
{ {
@ -66,6 +67,11 @@ namespace Ryujinx.Audio.Output
/// </summary> /// </summary>
private object _parentLock; private object _parentLock;
/// <summary>
/// The dispose state.
/// </summary>
private int _disposeState;
/// <summary> /// <summary>
/// Create a new <see cref="AudioOutputSystem"/>. /// Create a new <see cref="AudioOutputSystem"/>.
/// </summary> /// </summary>
@ -357,7 +363,10 @@ namespace Ryujinx.Audio.Output
public void Dispose() public void Dispose()
{ {
Dispose(true); if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
{
Dispose(true);
}
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)

View file

@ -94,6 +94,8 @@ namespace Ryujinx.Audio.Renderer.Server
private AudioRendererManager _manager; private AudioRendererManager _manager;
private int _disposeState;
public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent) public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent)
{ {
_manager = manager; _manager = manager;
@ -811,7 +813,10 @@ namespace Ryujinx.Audio.Renderer.Server
public void Dispose() public void Dispose()
{ {
Dispose(true); if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
{
Dispose(true);
}
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)

View file

@ -82,6 +82,11 @@ namespace Ryujinx.Audio.Renderer.Server
/// </summary> /// </summary>
public AudioProcessor Processor { get; } public AudioProcessor Processor { get; }
/// <summary>
/// The dispose state.
/// </summary>
private int _disposeState;
/// <summary> /// <summary>
/// Create a new <see cref="AudioRendererManager"/>. /// Create a new <see cref="AudioRendererManager"/>.
/// </summary> /// </summary>
@ -313,7 +318,10 @@ namespace Ryujinx.Audio.Renderer.Server
public void Dispose() public void Dispose()
{ {
Dispose(true); if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
{
Dispose(true);
}
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)

View file

@ -70,6 +70,7 @@ namespace Ryujinx.HLE.HOS
internal List<NfpDevice> NfpDevices { get; private set; } internal List<NfpDevice> NfpDevices { get; private set; }
internal ServerBase SmServer { get; private set; }
internal ServerBase BsdServer { get; private set; } internal ServerBase BsdServer { get; private set; }
internal ServerBase AudRenServer { get; private set; } internal ServerBase AudRenServer { get; private set; }
internal ServerBase AudOutServer { get; private set; } internal ServerBase AudOutServer { get; private set; }
@ -284,13 +285,11 @@ namespace Ryujinx.HLE.HOS
public void InitializeServices() public void InitializeServices()
{ {
IUserInterface sm = new IUserInterface(KernelContext); SmServer = new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext));
sm.TrySetServer(new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext)));
// Wait until SM server thread is done with initialization, // Wait until SM server thread is done with initialization,
// only then doing connections to SM is safe. // only then doing connections to SM is safe.
sm.Server.InitDone.WaitOne(); SmServer.InitDone.WaitOne();
sm.Server.InitDone.Dispose();
BsdServer = new ServerBase(KernelContext, "BsdServer"); BsdServer = new ServerBase(KernelContext, "BsdServer");
AudRenServer = new ServerBase(KernelContext, "AudioRendererServer"); AudRenServer = new ServerBase(KernelContext, "AudioRendererServer");
@ -419,7 +418,7 @@ namespace Ryujinx.HLE.HOS
SurfaceFlinger.Dispose(); SurfaceFlinger.Dispose();
// Terminate HLE services (must be done after the application is already terminated, // 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))) foreach (KProcess process in KernelContext.Processes.Values.Where(x => !x.Flags.HasFlag(ProcessCreationFlags.IsApplication)))
{ {
process.Terminate(); process.Terminate();

View file

@ -8,7 +8,7 @@ using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletCreator namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletCreator
{ {
class ILibraryAppletAccessor : IpcService, IDisposable class ILibraryAppletAccessor : DisposableIpcService
{ {
private KernelContext _kernelContext; private KernelContext _kernelContext;
@ -241,21 +241,24 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
return ResultCode.Success; 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) if (_normalOutDataEventHandle != 0)
{ {
_kernelContext.Syscall.CloseHandle(_normalOutDataEventHandle); _kernelContext.Syscall.CloseHandle(_normalOutDataEventHandle);
} }
if (_interactiveOutDataEventHandle != 0) if (_interactiveOutDataEventHandle != 0)
{ {
_kernelContext.Syscall.CloseHandle(_interactiveOutDataEventHandle); _kernelContext.Syscall.CloseHandle(_interactiveOutDataEventHandle);
}
} }
} }
} }

View file

@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Audio.AudioIn namespace Ryujinx.HLE.HOS.Services.Audio.AudioIn
{ {
class AudioInServer : IpcService, IDisposable class AudioInServer : DisposableIpcService
{ {
private IAudioIn _impl; private IAudioIn _impl;
@ -193,14 +193,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioIn
return ResultCode.Success; return ResultCode.Success;
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
Dispose(true); if (isDisposing)
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{ {
_impl.Dispose(); _impl.Dispose();
} }

View file

@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut
{ {
class AudioOutServer : IpcService, IDisposable class AudioOutServer : DisposableIpcService
{ {
private IAudioOut _impl; private IAudioOut _impl;
@ -174,14 +174,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut
return ResultCode.Success; return ResultCode.Success;
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
Dispose(true); if (isDisposing)
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{ {
_impl.Dispose(); _impl.Dispose();
} }

View file

@ -7,7 +7,7 @@ using System.Buffers;
namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
{ {
class AudioRendererServer : IpcService, IDisposable class AudioRendererServer : DisposableIpcService
{ {
private IAudioRenderer _impl; private IAudioRenderer _impl;
@ -172,14 +172,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
return result; return result;
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
Dispose(true); if (isDisposing)
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{ {
_impl.Dispose(); _impl.Dispose();
} }

View file

@ -1,12 +1,11 @@
using LibHac; using LibHac;
using LibHac.Bcat; using LibHac.Bcat;
using Ryujinx.Common; using Ryujinx.Common;
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{ {
class IDeliveryCacheDirectoryService : IpcService, IDisposable class IDeliveryCacheDirectoryService : DisposableIpcService
{ {
private LibHac.Bcat.Detail.Ipc.IDeliveryCacheDirectoryService _base; private LibHac.Bcat.Detail.Ipc.IDeliveryCacheDirectoryService _base;
@ -55,9 +54,12 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
_base?.Dispose(); if (isDisposing)
{
_base?.Dispose();
}
} }
} }
} }

View file

@ -1,11 +1,10 @@
using LibHac; using LibHac;
using LibHac.Bcat; using LibHac.Bcat;
using Ryujinx.Common; using Ryujinx.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{ {
class IDeliveryCacheFileService : IpcService, IDisposable class IDeliveryCacheFileService : DisposableIpcService
{ {
private LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService _base; private LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService _base;
@ -68,9 +67,12 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
_base?.Dispose(); if (isDisposing)
{
_base?.Dispose();
}
} }
} }
} }

View file

@ -1,11 +1,10 @@
using LibHac; using LibHac;
using LibHac.Bcat; using LibHac.Bcat;
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{ {
class IDeliveryCacheStorageService : IpcService, IDisposable class IDeliveryCacheStorageService : DisposableIpcService
{ {
private LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService _base; private LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService _base;
@ -60,9 +59,12 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
_base?.Dispose(); if (isDisposing)
{
_base?.Dispose();
}
} }
} }
} }

View file

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

View file

@ -9,7 +9,7 @@ using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
{ {
class INotificationService : IpcService, IDisposable class INotificationService : DisposableIpcService
{ {
private readonly UserId _userId; private readonly UserId _userId;
private readonly FriendServicePermissionLevel _permissionLevel; 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);
}
} }
} }
} }

View file

@ -1,10 +1,9 @@
using LibHac; using LibHac;
using LibHac.Fs; using LibHac.Fs;
using System;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
class IFile : IpcService, IDisposable class IFile : DisposableIpcService
{ {
private LibHac.Fs.Fsa.IFile _baseFile; private LibHac.Fs.Fsa.IFile _baseFile;
@ -82,14 +81,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
Dispose(true); if (isDisposing)
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{ {
_baseFile?.Dispose(); _baseFile?.Dispose();
} }

View file

@ -1,10 +1,9 @@
using LibHac; using LibHac;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using System;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
class IStorage : IpcService, IDisposable class IStorage : DisposableIpcService
{ {
private LibHac.Fs.IStorage _baseStorage; private LibHac.Fs.IStorage _baseStorage;
@ -53,14 +52,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
Dispose(true); if (isDisposing)
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{ {
_baseStorage?.Dispose(); _baseStorage?.Dispose();
} }

View file

@ -3,7 +3,7 @@ using LibHac;
namespace Ryujinx.HLE.HOS.Services.Fs namespace Ryujinx.HLE.HOS.Services.Fs
{ {
class ISaveDataInfoReader : IpcService, IDisposable class ISaveDataInfoReader : DisposableIpcService
{ {
private ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> _baseReader; private ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> _baseReader;
@ -29,9 +29,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
_baseReader.Dispose(); if (isDisposing)
{
_baseReader?.Dispose();
}
} }
} }
} }

View file

@ -265,5 +265,18 @@ namespace Ryujinx.HLE.HOS.Services
{ {
_parent = parent._parent; _parent = parent._parent;
} }
public virtual void DestroyAtExit()
{
foreach (object domainObject in _domainObjects.Values)
{
if (domainObject != this && domainObject is IDisposable disposableObj)
{
disposableObj.Dispose();
}
}
_domainObjects.Clear();
}
} }
} }

View file

@ -10,7 +10,7 @@ using System.Text;
namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
{ {
class IGeneralService : IpcService, IDisposable class IGeneralService : DisposableIpcService
{ {
private GeneralServiceDetail _generalServiceDetail; private GeneralServiceDetail _generalServiceDetail;
@ -197,9 +197,12 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
return (targetProperties, targetAddressInfo); return (targetProperties, targetAddressInfo);
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
GeneralServiceManager.Remove(_generalServiceDetail.ClientId); if (isDisposing)
{
GeneralServiceManager.Remove(_generalServiceDetail.ClientId);
}
} }
} }
} }

View file

@ -16,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
{ {
[Service("ldr:ro")] [Service("ldr:ro")]
[Service("ro:1")] // 7.0.0+ [Service("ro:1")] // 7.0.0+
class IRoInterface : IpcService, IDisposable class IRoInterface : DisposableIpcService
{ {
private const int MaxNrr = 0x40; private const int MaxNrr = 0x40;
private const int MaxNro = 0x40; private const int MaxNro = 0x40;
@ -571,14 +571,17 @@ namespace Ryujinx.HLE.HOS.Services.Ro
return ResultCode.Success; 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();
}
} }
} }
} }

View file

@ -4,6 +4,7 @@ using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc; using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Sm;
using System; using System;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Collections.Generic; using System.Collections.Generic;
@ -12,7 +13,7 @@ using System.Threading;
namespace Ryujinx.HLE.HOS.Services 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). // 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 // 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) public void AddSessionObj(KServerSession serverSession, IpcService obj)
{ {
// Ensure that the sever loop is running.
InitDone.WaitOne();
_selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle); _selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle);
AddSessionObj(serverSessionHandle, obj); AddSessionObj(serverSessionHandle, obj);
} }
@ -86,13 +90,9 @@ namespace Ryujinx.HLE.HOS.Services
_context.Syscall.ManageNamedPort("sm:", 50, out int serverPortHandle); _context.Syscall.ManageNamedPort("sm:", 50, out int serverPortHandle);
AddPort(serverPortHandle, SmObjectFactory); AddPort(serverPortHandle, SmObjectFactory);
}
InitDone.Set(); InitDone.Set();
}
else
{
InitDone.Dispose();
}
KThread thread = KernelStatic.GetCurrentThread(); KThread thread = KernelStatic.GetCurrentThread();
ulong messagePtr = thread.TlsAddress; ulong messagePtr = thread.TlsAddress;
@ -153,6 +153,8 @@ namespace Ryujinx.HLE.HOS.Services
_selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48)); _selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48));
} }
} }
Dispose();
} }
private bool Process(int serverSessionHandle, ulong recvListAddr) private bool Process(int serverSessionHandle, ulong recvListAddr)
@ -349,5 +351,30 @@ namespace Ryujinx.HLE.HOS.Services
return response; 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);
}
} }
} }

View file

@ -245,5 +245,12 @@ namespace Ryujinx.HLE.HOS.Services.Sm
return name; return name;
} }
public override void DestroyAtExit()
{
_commonServer.Dispose();
base.DestroyAtExit();
}
} }
} }

View file

@ -4,10 +4,12 @@ using System.Security.Cryptography;
namespace Ryujinx.HLE.HOS.Services.Spl namespace Ryujinx.HLE.HOS.Services.Spl
{ {
[Service("csrng")] [Service("csrng")]
class IRandomInterface : IpcService, IDisposable class IRandomInterface : DisposableIpcService
{ {
private RNGCryptoServiceProvider _rng; private RNGCryptoServiceProvider _rng;
private object _lock = new object();
public IRandomInterface(ServiceCtx context) public IRandomInterface(ServiceCtx context)
{ {
_rng = new RNGCryptoServiceProvider(); _rng = new RNGCryptoServiceProvider();
@ -26,14 +28,9 @@ namespace Ryujinx.HLE.HOS.Services.Spl
return ResultCode.Success; return ResultCode.Success;
} }
public void Dispose() protected override void Dispose(bool isDisposing)
{ {
Dispose(true); if (isDisposing)
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{ {
_rng.Dispose(); _rng.Dispose();
} }