Fix unsafe list manipulation in BeatmapDifficultyCache

This commit is contained in:
smoogipoo 2020-11-10 01:10:00 +09:00
parent d7c30f9b42
commit 66ea1572c7
1 changed files with 27 additions and 17 deletions

View File

@ -31,7 +31,7 @@ public class BeatmapDifficultyCache : MemoryCachingComponent<BeatmapDifficultyCa
private readonly ThreadedTaskScheduler updateScheduler = new ThreadedTaskScheduler(1, nameof(BeatmapDifficultyCache));
// All bindables that should be updated along with the current ruleset + mods.
private readonly LockedWeakList<BindableStarDifficulty> trackedBindables = new LockedWeakList<BindableStarDifficulty>();
private readonly WeakList<BindableStarDifficulty> trackedBindables = new WeakList<BindableStarDifficulty>();
[Resolved]
private BeatmapManager beatmapManager { get; set; }
@ -59,7 +59,10 @@ protected override void LoadComplete()
public IBindable<StarDifficulty> GetBindableDifficulty([NotNull] BeatmapInfo beatmapInfo, CancellationToken cancellationToken = default)
{
var bindable = createBindable(beatmapInfo, currentRuleset.Value, currentMods.Value, cancellationToken);
lock (trackedBindables)
trackedBindables.Add(bindable);
return bindable;
}
@ -86,7 +89,8 @@ public IBindable<StarDifficulty> GetBindableDifficulty([NotNull] BeatmapInfo bea
/// <param name="mods">The <see cref="Mod"/>s to get the difficulty with.</param>
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops computing the star difficulty.</param>
/// <returns>The <see cref="StarDifficulty"/>.</returns>
public Task<StarDifficulty> GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable<Mod> mods = null, CancellationToken cancellationToken = default)
public Task<StarDifficulty> GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable<Mod> mods = null,
CancellationToken cancellationToken = default)
{
// In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset.
rulesetInfo ??= beatmapInfo.Ruleset;
@ -147,6 +151,8 @@ public static DifficultyRating GetDifficultyRating(double starRating)
/// Updates all tracked <see cref="BindableStarDifficulty"/> using the current ruleset and mods.
/// </summary>
private void updateTrackedBindables()
{
lock (trackedBindables)
{
cancelTrackedBindableUpdate();
trackedUpdateCancellationSource = new CancellationTokenSource();
@ -159,11 +165,14 @@ private void updateTrackedBindables()
updateBindable(b, currentRuleset.Value, currentMods.Value, linkedSource.Token);
}
}
}
/// <summary>
/// Cancels the existing update of all tracked <see cref="BindableStarDifficulty"/> via <see cref="updateTrackedBindables"/>.
/// </summary>
private void cancelTrackedBindableUpdate()
{
lock (trackedBindables)
{
trackedUpdateCancellationSource?.Cancel();
trackedUpdateCancellationSource = null;
@ -176,6 +185,7 @@ private void cancelTrackedBindableUpdate()
linkedCancellationSources.Clear();
}
}
}
/// <summary>
/// Creates a new <see cref="BindableStarDifficulty"/> and triggers an initial value update.