Skip to content

Commit

Permalink
Fixed Some More Crashes that Reported Months Ago
Browse files Browse the repository at this point in the history
  • Loading branch information
DelnarErsike committed May 10, 2024
1 parent 285fcf0 commit fcdbfd4
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 55 deletions.
10 changes: 4 additions & 6 deletions Chummer/Backend/Equipment/Gear.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5349,12 +5349,10 @@ Improvement.ImprovementSource eSource
.ConfigureAwait(false);
if (objStack != null)
{
foreach (Gear objFociGear in objStack.Gear)
{
await objFociGear.ReaddImprovements(treGears, sbdOutdatedItems, lstInternalIdFilter,
Improvement.ImprovementSource.StackedFocus,
blnStackEquipped, token).ConfigureAwait(false);
}
await objStack.Gear.ForEachWithSideEffectsAsync(objFociGear =>
objFociGear.ReaddImprovements(treGears, sbdOutdatedItems, lstInternalIdFilter,
Improvement.ImprovementSource.StackedFocus,
blnStackEquipped, token), token: token).ConfigureAwait(false);
}
}

Expand Down
29 changes: 27 additions & 2 deletions Chummer/Backend/Helpers/AsyncFriendlyReaderWriterLock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ private IDisposable EnterReadLock(bool blnParentLockIsUpgradeable, CancellationT
"Entering a read lock after it has been disposed. Not fatal, just potentially a sign of bad code. Stacktrace:");
Debug.WriteLine(Environment.StackTrace);
#endif
return null;
return new DisposedReaderDummySemaphoreRelease(this);
}

token.ThrowIfCancellationRequested();
Expand Down Expand Up @@ -815,7 +815,7 @@ private Task<IAsyncDisposable> EnterReadLockAsync(bool blnParentLockIsUpgradeabl
"Entering a read lock after it has been disposed. Not fatal, just potentially a sign of bad code. Stacktrace:");
Debug.WriteLine(Environment.StackTrace);
#endif
return Task.FromResult<IAsyncDisposable>(null);
return Task.FromResult<IAsyncDisposable>(new DisposedReaderDummySemaphoreRelease(this));
}

if (token.IsCancellationRequested)
Expand Down Expand Up @@ -942,6 +942,31 @@ public async ValueTask DisposeAsync()
}
}

private readonly struct DisposedReaderDummySemaphoreRelease : IDisposable, IAsyncDisposable
{
private readonly AsyncFriendlyReaderWriterLock _objReaderWriterLock;

public DisposedReaderDummySemaphoreRelease(AsyncFriendlyReaderWriterLock objReaderWriterLock)
{
if (objReaderWriterLock != null && objReaderWriterLock._intDisposedStatus == 0)
throw new InvalidOperationException("Cannot assign dummy release to a non-disposed lock");
_objReaderWriterLock = objReaderWriterLock;
}

public void Dispose()
{
if (_objReaderWriterLock != null && _objReaderWriterLock._intDisposedStatus == 0)
throw new InvalidOperationException("Cannot assign dummy release to a non-disposed lock");
}

public ValueTask DisposeAsync()
{
if (_objReaderWriterLock != null && _objReaderWriterLock._intDisposedStatus == 0)
throw new InvalidOperationException("Cannot assign dummy release to a non-disposed lock");
return default;
}
}

private readonly struct SafeReaderSemaphoreRelease : IDisposable, IAsyncDisposable
{
private readonly LinkedAsyncRWLockHelper _objCurrentHelper;
Expand Down
48 changes: 24 additions & 24 deletions Chummer/Forms/Character Forms/CharacterCareer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4753,7 +4753,7 @@ await objQuality.GetCurrentDisplayNameShortAsync(token)
}

// Refresh Martial Art Techniques.
await CharacterObject.MartialArts.ForEachAsync(async objMartialArt =>
await CharacterObject.MartialArts.ForEachWithSideEffectsAsync(async objMartialArt =>
{
XmlNode objMartialArtNode
= await objMartialArt.GetNodeAsync(token).ConfigureAwait(false);
Expand All @@ -4776,7 +4776,7 @@ XmlNode objMartialArtNode
await objMartialArt.GetCurrentDisplayNameAsync(token).ConfigureAwait(false));
}

await objMartialArt.Techniques.ForEachAsync(async objTechnique =>
await objMartialArt.Techniques.ForEachWithSideEffectsAsync(async objTechnique =>
{
if (lstInternalIdFilter?.Contains(objTechnique.InternalId) == false)
return;
Expand All @@ -4800,7 +4800,7 @@ await objTechnique.GetCurrentDisplayNameAsync(token)
}, token).ConfigureAwait(false);

// Refresh Spells.
await CharacterObject.Spells.ForEachAsync(async objSpell =>
await CharacterObject.Spells.ForEachWithSideEffectsAsync(async objSpell =>
{
if (lstInternalIdFilter?.Contains(objSpell.InternalId) == false)
return;
Expand Down Expand Up @@ -4837,7 +4837,7 @@ await objTechnique.GetCurrentDisplayNameAsync(token)
}, token).ConfigureAwait(false);

// Refresh Adept Powers.
await CharacterObject.Powers.ForEachAsync(async objPower =>
await CharacterObject.Powers.ForEachWithSideEffectsAsync(async objPower =>
{
if (lstInternalIdFilter?.Contains(objPower.InternalId) == false)
return;
Expand All @@ -4864,7 +4864,7 @@ await objTechnique.GetCurrentDisplayNameAsync(token)
}, token).ConfigureAwait(false);

// Refresh Complex Forms.
await CharacterObject.ComplexForms.ForEachAsync(async objComplexForm =>
await CharacterObject.ComplexForms.ForEachWithSideEffectsAsync(async objComplexForm =>
{
if (lstInternalIdFilter?.Contains(objComplexForm.InternalId) == false)
return;
Expand Down Expand Up @@ -4904,7 +4904,7 @@ await objComplexForm
}, token).ConfigureAwait(false);

// Refresh AI Programs and Advanced Programs
await CharacterObject.AIPrograms.ForEachAsync(async objProgram =>
await CharacterObject.AIPrograms.ForEachWithSideEffectsAsync(async objProgram =>
{
if (lstInternalIdFilter?.Contains(objProgram.InternalId) == false)
return;
Expand Down Expand Up @@ -4943,7 +4943,7 @@ await objProgram.GetCurrentDisplayNameShortAsync(token)
}, token).ConfigureAwait(false);

// Refresh Critter Powers.
await CharacterObject.CritterPowers.ForEachAsync(async objPower =>
await CharacterObject.CritterPowers.ForEachWithSideEffectsAsync(async objPower =>
{
if (lstInternalIdFilter?.Contains(objPower.InternalId) == false)
return;
Expand Down Expand Up @@ -5095,7 +5095,7 @@ Cyberware objMatchingCyberware
}
}

await objCyberware.GearChildren.ForEachAsync(
await objCyberware.GearChildren.ForEachWithSideEffectsAsync(
objGear => objGear.ReaddImprovements(
treCyberware, sbdOutdatedItems, lstInternalIdFilter,
token: token), token).ConfigureAwait(false);
Expand Down Expand Up @@ -5183,7 +5183,7 @@ await treCyberware
}

// Refresh Armors.
await CharacterObject.Armor.ForEachAsync(async objArmor =>
await CharacterObject.Armor.ForEachWithSideEffectsAsync(async objArmor =>
{
// We're only re-apply improvements a list of items, not all of them
if (lstInternalIdFilter?.Contains(objArmor.InternalId) != false)
Expand Down Expand Up @@ -5223,7 +5223,7 @@ await objArmor.GetCurrentDisplayNameShortAsync(token)
}
}

await objArmor.ArmorMods.ForEachAsync(async objMod =>
await objArmor.ArmorMods.ForEachWithSideEffectsAsync(async objMod =>
{
// We're only re-apply improvements a list of items, not all of them
if (lstInternalIdFilter?.Contains(objMod.InternalId) != false)
Expand Down Expand Up @@ -5266,14 +5266,14 @@ await objMod
}
}

await objMod.GearChildren.ForEachAsync(objGear => objGear
await objMod.GearChildren.ForEachWithSideEffectsAsync(objGear => objGear
.ReaddImprovements(
treArmor, sbdOutdatedItems,
lstInternalIdFilter, token: token),
token).ConfigureAwait(false);
}, token).ConfigureAwait(false);

await objArmor.GearChildren.ForEachAsync(objGear => objGear
await objArmor.GearChildren.ForEachWithSideEffectsAsync(objGear => objGear
.ReaddImprovements(
treArmor, sbdOutdatedItems,
lstInternalIdFilter, token: token),
Expand All @@ -5283,7 +5283,7 @@ await objMod
}, token).ConfigureAwait(false);

// Refresh Gear.
await CharacterObject.Gear.ForEachAsync(async objGear =>
await CharacterObject.Gear.ForEachWithSideEffectsAsync(async objGear =>
{
await objGear
.ReaddImprovements(treGear, sbdOutdatedItems, lstInternalIdFilter, token: token)
Expand All @@ -5292,10 +5292,10 @@ await objGear
}, token).ConfigureAwait(false);

// Refresh Weapons Gear
await CharacterObject.Weapons.ForEachAsync(async objWeapon =>
await CharacterObject.Weapons.ForEachWithSideEffectsAsync(async objWeapon =>
{
await objWeapon.WeaponAccessories.ForEachAsync(
objAccessory => objAccessory.GearChildren.ForEachAsync(objGear =>
await objWeapon.WeaponAccessories.ForEachWithSideEffectsAsync(
objAccessory => objAccessory.GearChildren.ForEachWithSideEffectsAsync(objGear =>
objGear
.ReaddImprovements(
treWeapons, sbdOutdatedItems, lstInternalIdFilter,
Expand Down Expand Up @@ -9815,7 +9815,7 @@ private async void cmdChangeStartWeek_Click(object sender, EventArgs e)
int intWeekDiff = intWeek - objStart.Week;

// Update each of the CalendarWeek entries for the character.
await CharacterObject.Calendar.ForEachAsync(objWeek =>
await CharacterObject.Calendar.ForEachWithSideEffectsAsync(objWeek =>
{
objWeek.Week += intWeekDiff;
objWeek.Year += intYearDiff;
Expand Down Expand Up @@ -10104,7 +10104,7 @@ await LanguageManager.GetStringAsync("Message_DeleteImprovement", token: token)
await LanguageManager.GetStringAsync("Message_DeleteImprovementGroup", token: token)
.ConfigureAwait(false), token).ConfigureAwait(false))
return;
await CharacterObject.Improvements.ForEachAsync(objImprovement =>
await CharacterObject.Improvements.ForEachWithSideEffectsAsync(objImprovement =>
{
if (objImprovement.CustomGroup == strSelectedId)
objImprovement.CustomGroup = string.Empty;
Expand Down Expand Up @@ -10154,7 +10154,7 @@ private async void cmdArmorEquipAll_Click(object sender, EventArgs e)
if (objSelected is Location selectedLocation)
{
// Equip all of the Armor in the Armor Bundle.
await selectedLocation.Children.ForEachAsync(child =>
await selectedLocation.Children.ForEachWithSideEffectsAsync(child =>
{
if (child is Armor objArmor && objArmor.Location == selectedLocation)
{
Expand All @@ -10164,7 +10164,7 @@ private async void cmdArmorEquipAll_Click(object sender, EventArgs e)
}
else if (objSelected?.ToString() == "Node_SelectedArmor")
{
await CharacterObject.Armor.ForEachAsync(objArmor =>
await CharacterObject.Armor.ForEachWithSideEffectsAsync(objArmor =>
{
if (!objArmor.Equipped && objArmor.Location == null)
{
Expand Down Expand Up @@ -10194,7 +10194,7 @@ private async void cmdArmorUnEquipAll_Click(object sender, EventArgs e)
if (objSelected is Location selectedLocation)
{
// Equip all of the Armor in the Armor Bundle.
await selectedLocation.Children.ForEachAsync(child =>
await selectedLocation.Children.ForEachWithSideEffectsAsync(child =>
{
if (child is Armor objArmor && objArmor.Location == selectedLocation)
{
Expand All @@ -10204,7 +10204,7 @@ private async void cmdArmorUnEquipAll_Click(object sender, EventArgs e)
}
else if (objSelected?.ToString() == "Node_SelectedArmor")
{
await CharacterObject.Armor.ForEachAsync(objArmor =>
await CharacterObject.Armor.ForEachWithSideEffectsAsync(objArmor =>
{
if (!objArmor.Equipped && objArmor.Location == null)
{
Expand Down Expand Up @@ -14553,12 +14553,12 @@ string strDescription
string strNewLocation = frmPickText.MyForm.SelectedValue;

int i = -1;
await CharacterObject.ImprovementGroups.ForEachWithBreakAsync(async strLocation =>
await CharacterObject.ImprovementGroups.ForEachWithSideEffectsWithBreakAsync(async strLocation =>
{
++i;
if (strLocation != strOldLocation)
return true;
await CharacterObject.Improvements.ForEachAsync(objImprovement =>
await CharacterObject.Improvements.ForEachWithSideEffectsAsync(objImprovement =>
{
if (objImprovement.CustomGroup == strLocation)
objImprovement.CustomGroup = strNewLocation;
Expand Down

0 comments on commit fcdbfd4

Please sign in to comment.