From 81e9b86cdb4b2a01cc41b8e8a4dff2c9e3c13843 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Thu, 4 Nov 2021 20:27:21 -0300 Subject: [PATCH] Ensure syncpoints are released and event handles closed on channel close (#2812) --- .../NvHostChannel/NvHostChannelDeviceFile.cs | 12 ++++ .../NvHostChannel/NvHostGpuDeviceFile.cs | 72 +++++++++++++------ .../NvHostCtrl/NvHostCtrlDeviceFile.cs | 28 ++------ .../NvHostCtrl/Types/NvHostEvent.cs | 21 ++++-- 4 files changed, 84 insertions(+), 49 deletions(-) diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs index 3d9990309..edf554382 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs @@ -542,6 +542,18 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel { _host1xContext.Host1x.DestroyContext(_contextId); Channel.Dispose(); + + for (int i = 0; i < MaxModuleSyncpoint; i++) + { + if (ChannelSyncpoints[i] != 0) + { + _device.System.HostSyncpoint.ReleaseSyncpoint(ChannelSyncpoints[i]); + ChannelSyncpoints[i] = 0; + } + } + + _device.System.HostSyncpoint.ReleaseSyncpoint(_channelSyncpoint.Id); + _channelSyncpoint.Id = 0; } private static Host1xContext GetHost1XContext(GpuContext gpu, long pid) diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs index f27c065ed..46c19c6eb 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs @@ -12,11 +12,27 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel private KEvent _smExceptionBptPauseReportEvent; private KEvent _errorNotifierEvent; + private int _smExceptionBptIntReportEventHandle; + private int _smExceptionBptPauseReportEventHandle; + private int _errorNotifierEventHandle; + public NvHostGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, memory, owner) { - _smExceptionBptIntReportEvent = new KEvent(context.Device.System.KernelContext); - _smExceptionBptPauseReportEvent = new KEvent(context.Device.System.KernelContext); - _errorNotifierEvent = new KEvent(context.Device.System.KernelContext); + _smExceptionBptIntReportEvent = CreateEvent(context, out _smExceptionBptIntReportEventHandle); + _smExceptionBptPauseReportEvent = CreateEvent(context, out _smExceptionBptPauseReportEventHandle); + _errorNotifierEvent = CreateEvent(context, out _errorNotifierEventHandle); + } + + private static KEvent CreateEvent(ServiceCtx context, out int handle) + { + KEvent evnt = new KEvent(context.Device.System.KernelContext); + + if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + return evnt; } public override NvInternalResult Ioctl2(NvIoctl command, Span arguments, Span inlineInBuffer) @@ -39,41 +55,51 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel public override NvInternalResult QueryEvent(out int eventHandle, uint eventId) { // TODO: accurately represent and implement those events. - KEvent targetEvent = null; - switch (eventId) { case 0x1: - targetEvent = _smExceptionBptIntReportEvent; + eventHandle = _smExceptionBptIntReportEventHandle; break; case 0x2: - targetEvent = _smExceptionBptPauseReportEvent; + eventHandle = _smExceptionBptPauseReportEventHandle; break; case 0x3: - targetEvent = _errorNotifierEvent; + eventHandle = _errorNotifierEventHandle; + break; + default: + eventHandle = 0; break; } - if (targetEvent != null) - { - if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - } - else - { - eventHandle = 0; - - return NvInternalResult.InvalidInput; - } - - return NvInternalResult.Success; + return eventHandle != 0 ? NvInternalResult.Success : NvInternalResult.InvalidInput; } private NvInternalResult SubmitGpfifoEx(ref SubmitGpfifoArguments arguments, Span inlineData) { return SubmitGpfifo(ref arguments, inlineData); } + + public override void Close() + { + if (_smExceptionBptIntReportEventHandle != 0) + { + Context.Process.HandleTable.CloseHandle(_smExceptionBptIntReportEventHandle); + _smExceptionBptIntReportEventHandle = 0; + } + + if (_smExceptionBptPauseReportEventHandle != 0) + { + Context.Process.HandleTable.CloseHandle(_smExceptionBptPauseReportEventHandle); + _smExceptionBptPauseReportEventHandle = 0; + } + + if (_errorNotifierEventHandle != 0) + { + Context.Process.HandleTable.CloseHandle(_errorNotifierEventHandle); + _errorNotifierEventHandle = 0; + } + + base.Close(); + } } } diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlDeviceFile.cs index 9af1ce7d9..f9a2e03df 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlDeviceFile.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlDeviceFile.cs @@ -93,7 +93,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl return result; } - private KEvent QueryEvent(uint eventId) + private int QueryEvent(uint eventId) { lock (_events) { @@ -113,32 +113,18 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl if (eventSlot >= EventsCount || _events[eventSlot] == null || _events[eventSlot].Fence.Id != syncpointId) { - return null; + return 0; } - return _events[eventSlot].Event; + return _events[eventSlot].EventHandle; } } public override NvInternalResult QueryEvent(out int eventHandle, uint eventId) { - KEvent targetEvent = QueryEvent(eventId); + eventHandle = QueryEvent(eventId); - if (targetEvent != null) - { - if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - } - else - { - eventHandle = 0; - - return NvInternalResult.InvalidInput; - } - - return NvInternalResult.Success; + return eventHandle != 0 ? NvInternalResult.Success : NvInternalResult.InvalidInput; } private NvInternalResult SyncptRead(ref NvFence arguments) @@ -263,7 +249,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl hostEvent.State == NvHostEventState.Cancelled || hostEvent.State == NvHostEventState.Signaled) { - _events[userEventId].Dispose(); + _events[userEventId].CloseEvent(Context); _events[userEventId] = null; return NvInternalResult.Success; @@ -544,7 +530,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl } while (evnt.State != NvHostEventState.Signaled); } - evnt.Dispose(); + evnt.CloseEvent(Context); _events[i] = null; } diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs index f361b9375..d332bb044 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs @@ -1,6 +1,8 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu.Synchronization; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Nv.Types; using System; @@ -8,11 +10,12 @@ using System.Threading; namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl { - class NvHostEvent : IDisposable + class NvHostEvent { public NvFence Fence; public NvHostEventState State; public KEvent Event; + public int EventHandle; private uint _eventId; private NvHostSyncpt _syncpointManager; @@ -21,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl private NvFence _previousFailingFence; private uint _failingCount; - public object Lock = new object(); + public readonly object Lock = new object(); /// /// Max failing count until waiting on CPU. @@ -37,6 +40,11 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl Event = new KEvent(system.KernelContext); + if (KernelStatic.GetCurrentProcess().HandleTable.GenerateHandle(Event.ReadableEvent, out EventHandle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + _eventId = eventId; _syncpointManager = syncpointManager; @@ -165,10 +173,13 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl return res; } - public void Dispose() + public void CloseEvent(ServiceCtx context) { - Event.ReadableEvent.DecrementReferenceCount(); - Event.WritableEvent.DecrementReferenceCount(); + if (EventHandle != 0) + { + context.Process.HandleTable.CloseHandle(EventHandle); + EventHandle = 0; + } } } } \ No newline at end of file