Skip to content

Commit

Permalink
Various Misc. Safety Fixes Related to Reader-Writer Locking
Browse files Browse the repository at this point in the history
  • Loading branch information
DelnarErsike committed Mar 7, 2024
1 parent decf9a4 commit 16e0281
Show file tree
Hide file tree
Showing 69 changed files with 407 additions and 151 deletions.
6 changes: 3 additions & 3 deletions Chummer/Backend/Attributes/Attribute.Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace Chummer.Backend.Attributes
/// </summary>
[HubClassTag("Abbrev", true, "TotalValue", "TotalValue")]
[DebuggerDisplay("{" + nameof(_strAbbrev) + "}")]
public sealed class CharacterAttrib : INotifyMultiplePropertiesChangedAsync, IHasLockObject
public sealed class CharacterAttrib : INotifyMultiplePropertiesChangedAsync, IHasLockObject, IHasCharacterObject
{
private int _intMetatypeMin = 1;
private int _intMetatypeMax = 6;
Expand Down Expand Up @@ -74,6 +74,8 @@ public sealed class CharacterAttrib : INotifyMultiplePropertiesChangedAsync, IHa

public AsyncFriendlyReaderWriterLock LockObject { get; }

public Character CharacterObject => _objCharacter; // readonly member, no locking required

#region Constructor, Save, Load, and Print Methods

/// <summary>
Expand Down Expand Up @@ -286,8 +288,6 @@ public enum AttributeCategory

#region Properties

public Character CharacterObject => _objCharacter;

public AttributeCategory MetatypeCategory
{
get
Expand Down
4 changes: 3 additions & 1 deletion Chummer/Backend/Attributes/AttributeSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

namespace Chummer.Backend.Attributes
{
public sealed class AttributeSection : INotifyMultiplePropertiesChangedAsync, IHasLockObject
public sealed class AttributeSection : INotifyMultiplePropertiesChangedAsync, IHasLockObject, IHasCharacterObject
{
private int _intLoading = 1;

Expand Down Expand Up @@ -524,6 +524,8 @@ public UiPropertyChangerTracker(string strAbbrev)

public AsyncFriendlyReaderWriterLock LockObject { get; }

public Character CharacterObject => _objCharacter; // readonly member, no locking required

#region Constructor, Save, Load, Print Methods

public AttributeSection(Character objCharacter)
Expand Down
4 changes: 3 additions & 1 deletion Chummer/Backend/Characters/Character.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace Chummer
/// Class that holds all of the information that makes up a complete Character.
/// </summary>
[DebuggerDisplay("{CharacterName} ({FileName})")]
public sealed class Character : INotifyMultiplePropertiesChangedAsync, IHasMugshots, IHasName, IHasSource, IHasXmlDataNode, IHasLockObject
public sealed class Character : INotifyMultiplePropertiesChangedAsync, IHasMugshots, IHasName, IHasSource, IHasXmlDataNode, IHasLockObject, IHasCharacterObject
{
private static readonly TelemetryClient TelemetryClient = new TelemetryClient();
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
Expand Down Expand Up @@ -245,6 +245,8 @@ public sealed class Character : INotifyMultiplePropertiesChangedAsync, IHasMugsh

public AsyncFriendlyReaderWriterLock LockObject { get; }

public Character CharacterObject => this;

private readonly LockingOrderedSet<Func<Character, bool>> _setDoOnSaveCompleted;
private readonly LockingOrderedSet<Func<Character, CancellationToken, Task<bool>>> _setDoOnSaveCompletedAsync;

Expand Down
11 changes: 2 additions & 9 deletions Chummer/Backend/Characters/Contact.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public enum ContactType
/// A Contact or Enemy.
/// </summary>
[DebuggerDisplay("{" + nameof(Name) + "} ({DisplayRoleMethod(GlobalSettings.DefaultLanguage)})")]
public sealed class Contact : INotifyMultiplePropertiesChangedAsync, IHasName, IHasMugshots, IHasNotes, IHasInternalId, IHasLockObject
public sealed class Contact : INotifyMultiplePropertiesChangedAsync, IHasName, IHasMugshots, IHasNotes, IHasInternalId, IHasLockObject, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand Down Expand Up @@ -2679,14 +2679,7 @@ public async Task<int> GetForcedLoyaltyAsync(CancellationToken token = default)
}
}

public Character CharacterObject
{
get
{
using (LockObject.EnterReadLock())
return _objCharacter;
}
}
public Character CharacterObject => _objCharacter; // readonly member, no locking required

public Character LinkedCharacter
{
Expand Down
2 changes: 1 addition & 1 deletion Chummer/Backend/Characters/Spirit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public enum SpiritType
/// A Magician's Spirit or Technomancer's Sprite.
/// </summary>
[DebuggerDisplay("{Name}, \"{CritterName}\"")]
public sealed class Spirit : IHasInternalId, IHasName, IHasXmlDataNode, IHasMugshots, INotifyMultiplePropertiesChangedAsync, IHasNotes, IHasLockObject
public sealed class Spirit : IHasInternalId, IHasName, IHasXmlDataNode, IHasMugshots, INotifyMultiplePropertiesChangedAsync, IHasNotes, IHasLockObject, IHasCharacterObject
{
private Guid _guiId;
private string _strName = string.Empty;
Expand Down
4 changes: 3 additions & 1 deletion Chummer/Backend/Equipment/Armor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ namespace Chummer.Backend.Equipment
/// </summary>
[HubClassTag("SourceID", true, "TotalArmor", "Extra")]
[DebuggerDisplay("{DisplayName(GlobalSettings.InvariantCultureInfo, GlobalSettings.DefaultLanguage)}")]
public sealed class Armor : IHasInternalId, IHasName, IHasSourceId, IHasXmlDataNode, IHasNotes, ICanSell, IHasChildrenAndCost<Gear>, IHasCustomName, IHasLocation, ICanEquip, IHasSource, IHasRating, ICanSort, IHasWirelessBonus, IHasStolenProperty, ICanPaste, IHasGear, IHasMatrixAttributes, ICanBlackMarketDiscount, IDisposable, IAsyncDisposable
public sealed class Armor : IHasInternalId, IHasName, IHasSourceId, IHasXmlDataNode, IHasNotes, ICanSell, IHasChildrenAndCost<Gear>, IHasCustomName, IHasLocation, ICanEquip, IHasSource, IHasRating, ICanSort, IHasWirelessBonus, IHasStolenProperty, ICanPaste, IHasGear, IHasMatrixAttributes, ICanBlackMarketDiscount, IDisposable, IAsyncDisposable, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand Down Expand Up @@ -3552,5 +3552,7 @@ private async ValueTask DisposeSelfAsync()
await _lstArmorMods.DisposeAsync().ConfigureAwait(false);
await _lstGear.DisposeAsync().ConfigureAwait(false);
}

public Character CharacterObject => _objCharacter;
}
}
4 changes: 3 additions & 1 deletion Chummer/Backend/Equipment/ArmorMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace Chummer.Backend.Equipment
/// A piece of Armor Modification.
/// </summary>
[DebuggerDisplay("{DisplayName(GlobalSettings.InvariantCultureInfo, GlobalSettings.DefaultLanguage)}")]
public sealed class ArmorMod : IHasInternalId, IHasName, IHasSourceId, IHasXmlDataNode, IHasNotes, ICanSell, ICanEquip, IHasSource, IHasRating, ICanSort, IHasWirelessBonus, IHasStolenProperty, ICanPaste, IHasGear, ICanBlackMarketDiscount, IDisposable, IAsyncDisposable
public sealed class ArmorMod : IHasInternalId, IHasName, IHasSourceId, IHasXmlDataNode, IHasNotes, ICanSell, ICanEquip, IHasSource, IHasRating, ICanSort, IHasWirelessBonus, IHasStolenProperty, ICanPaste, IHasGear, ICanBlackMarketDiscount, IDisposable, IAsyncDisposable, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand Down Expand Up @@ -2310,5 +2310,7 @@ private ValueTask DisposeSelfAsync()
{
return _lstGear.DisposeAsync();
}

public Character CharacterObject => _objCharacter;
}
}
4 changes: 3 additions & 1 deletion Chummer/Backend/Equipment/Clip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

namespace Chummer.Backend.Equipment
{
public sealed class Clip
public sealed class Clip : IHasCharacterObject
{
private readonly Character _objCharacter;
private readonly Weapon _objWeapon;
Expand All @@ -51,6 +51,8 @@ internal Clip(Character objCharacter, WeaponAccessory objAccessory, Weapon objWe
/// </summary>
internal string OwnedBy => _objAccessory?.InternalId ?? _objWeapon?.InternalId;

public Character CharacterObject => _objCharacter;

internal int Ammo { get; set; }

public string DisplayWeaponName(CultureInfo objCulture = null, string strLanguage = "")
Expand Down
8 changes: 5 additions & 3 deletions Chummer/Backend/Equipment/Cyberware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ namespace Chummer.Backend.Equipment
public sealed class Cyberware : ICanPaste, IHasChildrenAndCost<Cyberware>, IHasGear, IHasName, IHasInternalId,
IHasSourceId, IHasXmlDataNode,
IHasMatrixAttributes, IHasNotes, ICanSell, IHasRating, IHasSource, ICanSort, IHasStolenProperty,
IHasWirelessBonus, ICanBlackMarketDiscount, IHasLockObject
IHasWirelessBonus, ICanBlackMarketDiscount, IHasLockObject, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand Down Expand Up @@ -1416,7 +1416,7 @@ await GetCurrentDisplayNameShortAsync(token).ConfigureAwait(false), blnCreateImp
this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, Children),
token), token);
}
else if (await Children.CountAsync(token).ConfigureAwait(false) > 0)
else if (await Children.GetCountAsync(token).ConfigureAwait(false) > 0)
await CyberwareChildrenOnCollectionChanged(this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, Children), token).ConfigureAwait(false);
}
Expand Down Expand Up @@ -4984,7 +4984,7 @@ public async Task SetRatingAsync(int value, CancellationToken token = default)
value = Math.Max(Math.Min(value, await GetMaxRatingAsync(token).ConfigureAwait(false)), await GetMinRatingAsync(token).ConfigureAwait(false));
if (Interlocked.Exchange(ref _intRating, value) == value)
return;
if (await GearChildren.CountAsync(token).ConfigureAwait(false) > 0)
if (await GearChildren.GetCountAsync(token).ConfigureAwait(false) > 0)
{
await GearChildren.ForEachAsync(async objChild =>
{
Expand Down Expand Up @@ -11442,5 +11442,7 @@ private async ValueTask DisposeSelfAsync()

/// <inheritdoc />
public AsyncFriendlyReaderWriterLock LockObject { get; }

public Character CharacterObject => _objCharacter; // readonly member, no locking required
}
}
8 changes: 6 additions & 2 deletions Chummer/Backend/Equipment/Drugs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

namespace Chummer.Backend.Equipment
{
public sealed class Drug : IHasName, IHasSourceId, IHasXmlDataNode, ICanSort, IHasStolenProperty, ICanRemove, IDisposable, IAsyncDisposable
public sealed class Drug : IHasName, IHasSourceId, IHasXmlDataNode, ICanSort, IHasStolenProperty, ICanRemove, IDisposable, IAsyncDisposable, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand Down Expand Up @@ -986,6 +986,8 @@ public bool Stolen
set => _blnStolen = value;
}

public Character CharacterObject => _objCharacter;

#endregion Properties

#region UI Methods
Expand Down Expand Up @@ -1614,7 +1616,7 @@ public ValueTask DisposeAsync()
/// <summary>
/// Drug Component.
/// </summary>
public class DrugComponent : IHasName, IHasInternalId, IHasXmlDataNode
public class DrugComponent : IHasName, IHasInternalId, IHasXmlDataNode, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand All @@ -1640,6 +1642,8 @@ public DrugComponent(Character objCharacter)
_objCharacter = objCharacter;
}

public Character CharacterObject => _objCharacter;

#region Constructor, Create, Save, Load, and Print Methods

public void Load(XmlNode objXmlData)
Expand Down
11 changes: 4 additions & 7 deletions Chummer/Backend/Equipment/Gear.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ namespace Chummer.Backend.Equipment
[DebuggerDisplay("{DisplayName(GlobalSettings.InvariantCultureInfo, GlobalSettings.DefaultLanguage)}")]
public sealed class Gear : IHasChildrenAndCost<Gear>, IHasName, IHasSourceId, IHasInternalId, IHasXmlDataNode, IHasMatrixAttributes,
IHasNotes, ICanSell, IHasLocation, ICanEquip, IHasSource, IHasRating, INotifyMultiplePropertiesChangedAsync, ICanSort,
IHasStolenProperty, ICanPaste, IHasWirelessBonus, IHasGear, ICanBlackMarketDiscount, IDisposable, IAsyncDisposable
IHasStolenProperty, ICanPaste, IHasWirelessBonus, IHasGear, ICanBlackMarketDiscount, IDisposable, IAsyncDisposable, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand Down Expand Up @@ -2035,6 +2035,8 @@ public async Task PrintWeaponBonusEntries(XmlWriter objWriter, CultureInfo objCu

#region Properties

public Character CharacterObject => _objCharacter;

/// <summary>
/// Guid of the object from the data. You probably want to use SourceIDString instead.
/// </summary>
Expand Down Expand Up @@ -2103,11 +2105,6 @@ public XmlNode FlechetteWeaponBonus
set => _nodFlechetteWeaponBonus = value;
}

/// <summary>
/// Character to which the gear is assigned.
/// </summary>
public Character CharacterObject => _objCharacter;

/// <summary>
/// Name.
/// </summary>
Expand Down Expand Up @@ -4197,7 +4194,7 @@ public async Task<decimal> GetCapacityRemainingAsync(CancellationToken token = d
out decCapacity))
decCapacity = 0;

if (await Children.CountAsync(token).ConfigureAwait(false) > 0)
if (await Children.GetCountAsync(token).ConfigureAwait(false) > 0)
{
// Run through its Children and deduct the Capacity costs.
decCapacity -= await Children.SumAsync(async x => await x.GetPluginCapacityAsync(token).ConfigureAwait(false) * x.Quantity, token).ConfigureAwait(false);
Expand Down
4 changes: 3 additions & 1 deletion Chummer/Backend/Equipment/Grade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace Chummer.Backend.Equipment
/// Grade of Cyberware or Bioware.
/// </summary>
[DebuggerDisplay("{DisplayName(GlobalSettings.DefaultLanguage)}")]
public class Grade : IHasName, IHasSourceId, IHasInternalId, IHasXmlDataNode
public class Grade : IHasName, IHasSourceId, IHasInternalId, IHasXmlDataNode, IHasCharacterObject
{
private readonly Character _objCharacter;
private Guid _guiSourceID = Guid.Empty;
Expand Down Expand Up @@ -190,6 +190,8 @@ public static string GetDataFileNameFromImprovementSource(Improvement.Improvemen

#region Properties

public Character CharacterObject => _objCharacter;

/// <summary>
/// Internal identifier which will be used to identify this grade.
/// </summary>
Expand Down
4 changes: 3 additions & 1 deletion Chummer/Backend/Equipment/Lifestyle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public enum LifestyleIncrement
/// Lifestyle.
/// </summary>
[DebuggerDisplay("{DisplayName(GlobalSettings.DefaultLanguage)}")]
public sealed class Lifestyle : IHasInternalId, IHasXmlDataNode, IHasNotes, ICanRemove, IHasCustomName, IHasSourceId, IHasSource, ICanSort, INotifyMultiplePropertiesChangedAsync, IHasLockObject, IHasCost
public sealed class Lifestyle : IHasInternalId, IHasXmlDataNode, IHasNotes, ICanRemove, IHasCustomName, IHasSourceId, IHasSource, ICanSort, INotifyMultiplePropertiesChangedAsync, IHasLockObject, IHasCost, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand Down Expand Up @@ -4296,5 +4296,7 @@ public async ValueTask DisposeAsync()

/// <inheritdoc />
public AsyncFriendlyReaderWriterLock LockObject { get; }

public Character CharacterObject => _objCharacter; // readonly member, no locking required
}
}
4 changes: 3 additions & 1 deletion Chummer/Backend/Equipment/LifestyleQuality.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
namespace Chummer.Backend.Equipment
{
[DebuggerDisplay("{DisplayName(GlobalSettings.DefaultLanguage)}")]
public sealed class LifestyleQuality : IHasInternalId, IHasName, IHasSourceId, IHasXmlDataNode, IHasNotes, IHasSource, ICanRemove, INotifyMultiplePropertiesChangedAsync, IHasLockObject
public sealed class LifestyleQuality : IHasInternalId, IHasName, IHasSourceId, IHasXmlDataNode, IHasNotes, IHasSource, ICanRemove, INotifyMultiplePropertiesChangedAsync, IHasLockObject, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand Down Expand Up @@ -2623,5 +2623,7 @@ await ParentLifestyle

/// <inheritdoc />
public AsyncFriendlyReaderWriterLock LockObject { get; }

public Character CharacterObject => _objCharacter; // readonly member, no locking required
}
}
5 changes: 3 additions & 2 deletions Chummer/Backend/Equipment/Vehicle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
using System.Xml;
using System.Xml.XPath;
using Chummer.Annotations;
using Chummer.Backend.Attributes;
using NLog;
using TreeNode = System.Windows.Forms.TreeNode;
using TreeNodeCollection = System.Windows.Forms.TreeNodeCollection;
Expand All @@ -44,7 +43,7 @@ namespace Chummer.Backend.Equipment
/// </summary>
[HubClassTag("SourceID", true, "Name", null)]
[DebuggerDisplay("{DisplayName(GlobalSettings.DefaultLanguage)}")]
public sealed class Vehicle : IHasInternalId, IHasName, IHasSourceId, IHasXmlDataNode, IHasMatrixAttributes, IHasNotes, ICanSell, IHasCustomName, IHasPhysicalConditionMonitor, IHasLocation, IHasSource, ICanSort, IHasGear, IHasStolenProperty, ICanPaste, ICanBlackMarketDiscount, IDisposable, IAsyncDisposable
public sealed class Vehicle : IHasInternalId, IHasName, IHasSourceId, IHasXmlDataNode, IHasMatrixAttributes, IHasNotes, ICanSell, IHasCustomName, IHasPhysicalConditionMonitor, IHasLocation, IHasSource, ICanSort, IHasGear, IHasStolenProperty, ICanPaste, ICanBlackMarketDiscount, IDisposable, IAsyncDisposable, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand Down Expand Up @@ -89,6 +88,8 @@ public sealed class Vehicle : IHasInternalId, IHasName, IHasSourceId, IHasXmlDat

private readonly Character _objCharacter;

public Character CharacterObject => _objCharacter; // readonly member, no locking required

private string _strDeviceRating = string.Empty;
private string _strAttack = string.Empty;
private string _strSleaze = string.Empty;
Expand Down
4 changes: 3 additions & 1 deletion Chummer/Backend/Equipment/VehicleMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace Chummer.Backend.Equipment
/// Vehicle Modification.
/// </summary>
[DebuggerDisplay("{DisplayName(GlobalSettings.InvariantCultureInfo, GlobalSettings.DefaultLanguage)}")]
public sealed class VehicleMod : IHasInternalId, IHasName, IHasSourceId, IHasXmlDataNode, IHasNotes, ICanEquip, IHasSource, IHasRating, ICanSort, IHasStolenProperty, ICanPaste, ICanSell, ICanBlackMarketDiscount, IDisposable, IAsyncDisposable
public sealed class VehicleMod : IHasInternalId, IHasName, IHasSourceId, IHasXmlDataNode, IHasNotes, ICanEquip, IHasSource, IHasRating, ICanSort, IHasStolenProperty, ICanPaste, ICanSell, ICanBlackMarketDiscount, IDisposable, IAsyncDisposable, IHasCharacterObject
{
private static readonly Lazy<Logger> s_ObjLogger = new Lazy<Logger>(LogManager.GetCurrentClassLogger);
private static Logger Log => s_ObjLogger.Value;
Expand Down Expand Up @@ -2654,5 +2654,7 @@ private async ValueTask DisposeSelfAsync()
await _lstVehicleWeapons.DisposeAsync().ConfigureAwait(false);
await _lstCyberware.DisposeAsync().ConfigureAwait(false);
}

public Character CharacterObject => _objCharacter;
}
}

0 comments on commit 16e0281

Please sign in to comment.