Skip to content

Switch backing store for callback-array to an immutable structure so it cannot change as we are enumerating over it.#61671

Merged
CyrusNajmabadi merged 3 commits intodotnet:mainfrom
CyrusNajmabadi:safeEnumeration
Jun 3, 2022
Merged

Switch backing store for callback-array to an immutable structure so it cannot change as we are enumerating over it.#61671
CyrusNajmabadi merged 3 commits intodotnet:mainfrom
CyrusNajmabadi:safeEnumeration

Conversation

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi commented Jun 2, 2022

Fixes AB#1545234

There's been an intermittent stability issue that was caused by the view-visibility work i added a while back. The core issue here is that we were enumerating a mutable collection of callbacks, invoking them during iteration. It was possible for the callback to then perform work that would cause a mutation of the collection being iterated.

An example of this was a callback that set a TaskCompletionSource to completed. When completed, TPL could inline execution of the continuations of that task onto that thread, and those continuations could then register/unregister callbacks.

Fix here is to switch to immutable collections so that iteration is always safe. (Another option was to make a copy of the collection while iterating, but i felt this was cleaner).

…it cannot change as we are enumerating over it.
@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner June 2, 2022 22:08
@CyrusNajmabadi CyrusNajmabadi requested a review from a team June 2, 2022 22:08
@ghost ghost added the Area-IDE label Jun 2, 2022
/// The callbacks that want to be notified when our <see cref="TextViews"/> change visibility. Stored as an
/// <see cref="ImmutableHashSet{T}"/> so we can enumerate it safely without it changing underneath us.
/// </summary>
public ImmutableHashSet<Action> Callbacks = ImmutableHashSet<Action>.Empty;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

@jmarolf jmarolf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a test where we enumerate the collection that would fail before this change?

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Sure. Let me write a unit test that directly interacts with this.

@CyrusNajmabadi CyrusNajmabadi enabled auto-merge June 2, 2022 22:48
/// The callbacks that want to be notified when our <see cref="TextViews"/> change visibility. Stored as an
/// <see cref="ImmutableHashSet{T}"/> so we can enumerate it safely without it changing underneath us.
/// </summary>
public ImmutableHashSet<Action> Callbacks { get; private set; } = ImmutableHashSet<Action>.Empty;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❔ Do we care about order here? Normal events always and HashSet<T> often preserves "registration order is callback order", but ImmutableHashSet<T> will not.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I hadn't ever thought it was relevant, but I'm ok adding that constraint.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, i'm ok with this as is. We coudl def make this an array in teh future though if we think it's appropriate.

@CyrusNajmabadi CyrusNajmabadi merged commit ceb02a6 into dotnet:main Jun 3, 2022
@ghost ghost added this to the Next milestone Jun 3, 2022
@CyrusNajmabadi CyrusNajmabadi deleted the safeEnumeration branch June 3, 2022 14:16
@RikkiGibson RikkiGibson modified the milestones: Next, 17.3 P3 Jun 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants