From d054d16c100f5d099c38f79ce11f300edd37f26c Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sat, 8 Apr 2023 00:53:15 +0200 Subject: [PATCH 1/4] Added reference counting to update queues to prevent premature disposes when used in multiple devices --- RGB.NET.Core/Devices/AbstractRGBDevice.cs | 9 +++- .../Extensions/ReferenceCountingExtension.cs | 6 +++ .../Misc/AbstractReferenceCounting.cs | 41 +++++++++++++++++++ RGB.NET.Core/Misc/IReferenceCounting.cs | 21 ++++++++++ RGB.NET.Core/RGB.NET.Core.csproj.DotSettings | 1 + RGB.NET.Core/Update/Devices/IUpdateQueue.cs | 2 +- RGB.NET.Core/Update/Devices/UpdateQueue.cs | 8 +++- 7 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 RGB.NET.Core/Extensions/ReferenceCountingExtension.cs create mode 100644 RGB.NET.Core/Misc/AbstractReferenceCounting.cs create mode 100644 RGB.NET.Core/Misc/IReferenceCounting.cs diff --git a/RGB.NET.Core/Devices/AbstractRGBDevice.cs b/RGB.NET.Core/Devices/AbstractRGBDevice.cs index 6ac90da..faaf147 100644 --- a/RGB.NET.Core/Devices/AbstractRGBDevice.cs +++ b/RGB.NET.Core/Devices/AbstractRGBDevice.cs @@ -85,6 +85,8 @@ public abstract class AbstractRGBDevice : Placeable, IRGBDevice : Placeable, IRGBDevice public virtual void Dispose() { - try { UpdateQueue.Dispose(); } catch { /* :( */ } + try + { + UpdateQueue.RemoveReferencingObject(this); + UpdateQueue.Dispose(); + } + catch { /* :( */ } try { LedMapping.Clear(); } catch { /* this really shouldn't happen */ } IdGenerator.ResetCounter(GetType().Assembly); diff --git a/RGB.NET.Core/Extensions/ReferenceCountingExtension.cs b/RGB.NET.Core/Extensions/ReferenceCountingExtension.cs new file mode 100644 index 0000000..58039eb --- /dev/null +++ b/RGB.NET.Core/Extensions/ReferenceCountingExtension.cs @@ -0,0 +1,6 @@ +namespace RGB.NET.Core; + +public static class ReferenceCountingExtension +{ + public static bool HasActiveReferences(this IReferenceCounting target) => target.ActiveReferenceCount > 0; +} \ No newline at end of file diff --git a/RGB.NET.Core/Misc/AbstractReferenceCounting.cs b/RGB.NET.Core/Misc/AbstractReferenceCounting.cs new file mode 100644 index 0000000..070138a --- /dev/null +++ b/RGB.NET.Core/Misc/AbstractReferenceCounting.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; + +namespace RGB.NET.Core; + +public abstract class AbstractReferenceCounting : IReferenceCounting +{ + #region Properties & Fields + + private readonly HashSet _referencingObjects = new(); + + /// + public int ActiveReferenceCount + { + get + { + lock (_referencingObjects) + return _referencingObjects.Count; + } + } + + #endregion + + #region Methods + + /// + public void AddReferencingObject(object obj) + { + lock (_referencingObjects) + if (!_referencingObjects.Contains(obj)) + _referencingObjects.Add(obj); + } + + /// + public void RemoveReferencingObject(object obj) + { + lock (_referencingObjects) + _referencingObjects.Remove(obj); + } + + #endregion +} \ No newline at end of file diff --git a/RGB.NET.Core/Misc/IReferenceCounting.cs b/RGB.NET.Core/Misc/IReferenceCounting.cs new file mode 100644 index 0000000..d8bcb28 --- /dev/null +++ b/RGB.NET.Core/Misc/IReferenceCounting.cs @@ -0,0 +1,21 @@ +namespace RGB.NET.Core; + +public interface IReferenceCounting +{ + /// + /// Gets the amount of currently registered referencing objects. + /// + public int ActiveReferenceCount { get; } + + /// + /// Adds the given object to the list of referencing objects. + /// + /// The object to add. + public void AddReferencingObject(object obj); + + /// + /// Removes the given object from the list of referencing objects. + /// + /// The object to remove. + public void RemoveReferencingObject(object obj); +} \ No newline at end of file diff --git a/RGB.NET.Core/RGB.NET.Core.csproj.DotSettings b/RGB.NET.Core/RGB.NET.Core.csproj.DotSettings index bf7655f..7f9a6e2 100644 --- a/RGB.NET.Core/RGB.NET.Core.csproj.DotSettings +++ b/RGB.NET.Core/RGB.NET.Core.csproj.DotSettings @@ -16,6 +16,7 @@ True True True + True True True True diff --git a/RGB.NET.Core/Update/Devices/IUpdateQueue.cs b/RGB.NET.Core/Update/Devices/IUpdateQueue.cs index 348c16e..bf4011c 100644 --- a/RGB.NET.Core/Update/Devices/IUpdateQueue.cs +++ b/RGB.NET.Core/Update/Devices/IUpdateQueue.cs @@ -8,7 +8,7 @@ namespace RGB.NET.Core; /// /// The identifier used to identify the data processed by this queue. /// The type of the data processed by this queue. -public interface IUpdateQueue : IDisposable +public interface IUpdateQueue : IReferenceCounting, IDisposable where TIdentifier : notnull { /// diff --git a/RGB.NET.Core/Update/Devices/UpdateQueue.cs b/RGB.NET.Core/Update/Devices/UpdateQueue.cs index 1cc5eca..bdd0868 100644 --- a/RGB.NET.Core/Update/Devices/UpdateQueue.cs +++ b/RGB.NET.Core/Update/Devices/UpdateQueue.cs @@ -10,7 +10,7 @@ namespace RGB.NET.Core; /// /// The type of the key used to identify some data. /// The type of the data. -public abstract class UpdateQueue : IUpdateQueue +public abstract class UpdateQueue : AbstractReferenceCounting, IUpdateQueue where TIdentifier : notnull { #region Properties & Fields @@ -112,8 +112,14 @@ public abstract class UpdateQueue : IUpdateQueue + /// + /// Disposes this queue. + /// Checks if any referencing objects are registered and if so, will return without disposing! + /// public virtual void Dispose() { + if (this.HasActiveReferences()) return; + _updateTrigger.Starting -= OnStartup; _updateTrigger.Update -= OnUpdate; From 5b514ff9629d756c36c769bfa1055cbac0f8c079 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sat, 8 Apr 2023 14:42:56 +0200 Subject: [PATCH 2/4] Moved reference check for UpdateQueue disposal to the caller to prevent issues with Dispose-overrides --- RGB.NET.Core/Devices/AbstractRGBDevice.cs | 3 ++- RGB.NET.Core/Update/Devices/UpdateQueue.cs | 6 ------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/RGB.NET.Core/Devices/AbstractRGBDevice.cs b/RGB.NET.Core/Devices/AbstractRGBDevice.cs index faaf147..596625c 100644 --- a/RGB.NET.Core/Devices/AbstractRGBDevice.cs +++ b/RGB.NET.Core/Devices/AbstractRGBDevice.cs @@ -162,7 +162,8 @@ public abstract class AbstractRGBDevice : Placeable, IRGBDevice : AbstractReferenceCountin } /// - /// - /// Disposes this queue. - /// Checks if any referencing objects are registered and if so, will return without disposing! - /// public virtual void Dispose() { - if (this.HasActiveReferences()) return; - _updateTrigger.Starting -= OnStartup; _updateTrigger.Update -= OnUpdate; From 818678fdf228a8dc08d9fc03092557ef189ddc09 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sat, 8 Apr 2023 21:10:12 +0200 Subject: [PATCH 3/4] Added PID for Razer Ornata V3 fixes #309 --- RGB.NET.Devices.Razer/RazerDeviceProvider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/RGB.NET.Devices.Razer/RazerDeviceProvider.cs b/RGB.NET.Devices.Razer/RazerDeviceProvider.cs index f31174e..04edecc 100644 --- a/RGB.NET.Devices.Razer/RazerDeviceProvider.cs +++ b/RGB.NET.Devices.Razer/RazerDeviceProvider.cs @@ -108,6 +108,7 @@ public class RazerDeviceProvider : AbstractRGBDeviceProvider { 0x0266, RGBDeviceType.Keyboard, "Huntsman V2", LedMappings.Keyboard, RazerEndpointType.Keyboard }, { 0x026C, RGBDeviceType.Keyboard, "Huntsman V2", LedMappings.Keyboard, RazerEndpointType.Keyboard }, { 0x028D, RGBDeviceType.Keyboard, "BlackWidow V4", LedMappings.Keyboard, RazerEndpointType.Keyboard }, + { 0x02A1, RGBDeviceType.Keyboard, "Ornata V3", LedMappings.Keyboard, RazerEndpointType.Keyboard }, // Mice { 0x0013, RGBDeviceType.Mouse, "Orochi 2011", LedMappings.Mouse, RazerEndpointType.Mouse }, From 10183fb27014792062c0dfb10ffb9cc7b96064be Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sun, 9 Apr 2023 16:36:27 +0200 Subject: [PATCH 4/4] Added dispose-check to corsairs update queue --- RGB.NET.Devices.Corsair/Generic/CorsairDeviceUpdateQueue.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RGB.NET.Devices.Corsair/Generic/CorsairDeviceUpdateQueue.cs b/RGB.NET.Devices.Corsair/Generic/CorsairDeviceUpdateQueue.cs index fa743e8..8bea2eb 100644 --- a/RGB.NET.Devices.Corsair/Generic/CorsairDeviceUpdateQueue.cs +++ b/RGB.NET.Devices.Corsair/Generic/CorsairDeviceUpdateQueue.cs @@ -13,6 +13,8 @@ public class CorsairDeviceUpdateQueue : UpdateQueue { #region Properties & Fields + private bool _isDisposed = false; + private readonly _CorsairDeviceInfo _device; private readonly nint _colorPtr; @@ -42,6 +44,7 @@ public class CorsairDeviceUpdateQueue : UpdateQueue { try { + if (_isDisposed) throw new ObjectDisposedException(nameof(CorsairDeviceUpdateQueue)); if (!_CUESDK.IsConnected) return false; Span<_CorsairLedColor> colors = new((void*)_colorPtr, dataSet.Length); @@ -71,6 +74,7 @@ public class CorsairDeviceUpdateQueue : UpdateQueue { base.Dispose(); + _isDisposed = true; Marshal.FreeHGlobal(_colorPtr); GC.SuppressFinalize(this);