Skip to content

Replace GCX_COOP with EBR for EEHashTable bucket reclamation#124822

Merged
AaronRobinsonMSFT merged 5 commits intodotnet:mainfrom
AaronRobinsonMSFT:ebr-eehash
Feb 27, 2026
Merged

Replace GCX_COOP with EBR for EEHashTable bucket reclamation#124822
AaronRobinsonMSFT merged 5 commits intodotnet:mainfrom
AaronRobinsonMSFT:ebr-eehash

Conversation

@AaronRobinsonMSFT
Copy link
Member

@AaronRobinsonMSFT AaronRobinsonMSFT commented Feb 24, 2026

Replace cooperative GC mode transitions (GCX_COOP_NO_THREAD_BROKEN) with Epoch-Based Reclamation for safe deferred deletion of old EEHashTable bucket arrays during resize.

Changes

  • Add shared g_EbrCollector collector with initialization in ceemain.cpp and cleanup in f inalizerthread.cpp
  • Add AllocateEEHashBuckets FreeEEHashBuckets helpers in eehash.cpp, following the same pattern as HashMap's AllocateBuckets FreeBuckets
  • Remove SyncClean::AddEEHashTable and associated cleanup infrastructure from syncclean.cpp/.hpp
  • Remove redundant MemoryBarrier() before VolatilePtr::Store() — release semantics already provide the ordering guarantee

Follow-up to #124307 (Replace HashMap COOP transitions with EBR). Specifically see #124307 (comment).

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.

@AaronRobinsonMSFT AaronRobinsonMSFT added this to the 11.0.0 milestone Feb 24, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR replaces the prior GC cooperative-mode based scheme for safely reclaiming obsolete EEHashTable bucket arrays with Epoch-Based Reclamation (EBR), aligning EEHashTable resizing behavior with the earlier HashMap EBR work.

Changes:

  • Add a dedicated global EBR collector (g_EEHashEbr) and initialize it during EE startup; trigger cleanup from the finalizer thread’s “extra work” loop.
  • Refactor EEHashTable bucket allocation/freeing into helpers and use EBR critical regions + deferred deletion during table growth instead of GCX_COOP_NO_THREAD_BROKEN + SyncClean.
  • Simplify SyncClean by removing the EEHashTable-specific cleanup list and related APIs.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/coreclr/vm/syncclean.hpp Removes EEHashTable cleanup list API; leaves SyncClean::CleanUp() only.
src/coreclr/vm/syncclean.cpp Removes EEHashTable cleanup list storage and freeing logic.
src/coreclr/vm/finalizerthread.cpp Adds g_EEHashEbr cleanup request detection and processing in finalizer extra-work path.
src/coreclr/vm/eehash.inl Replaces COOP transitions with EBR critical regions; defers old bucket array deletion via EBR during growth.
src/coreclr/vm/eehash.h Declares EEHashTable bucket allocation/free helpers.
src/coreclr/vm/eehash.cpp Implements AllocateEEHashBuckets / FreeEEHashBuckets.
src/coreclr/vm/ebr.h Declares extern EbrCollector g_EEHashEbr.
src/coreclr/vm/ebr.cpp Defines global g_EEHashEbr.
src/coreclr/vm/ceemain.cpp Initializes g_EEHashEbr during EE startup.

Replace cooperative GC mode transitions (GCX_COOP_NO_THREAD_BROKEN) with
Epoch-Based Reclamation for safe deferred deletion of old EEHashTable
bucket arrays during resize.

- Add dedicated g_EEHashEbr collector (init, cleanup, critical regions)
- Add AllocateEEHashBuckets/FreeEEHashBuckets helpers in eehash.cpp
- Remove SyncClean::AddEEHashTable and associated cleanup infrastructure
- Remove redundant MemoryBarrier before VolatilePtr::Store (release semantics)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

The per-thread EbrThreadData is a single thread_local with one m_pCollector
field, so it can only be associated with one collector at a time. Having
two collectors caused the same TLS node to be linked into both thread
lists, corrupting epoch tracking and thread detach cleanup.

Both HashMap and EEHashTable use generic byte-array reclamation, so a
single shared collector is sufficient. Added an assertion in
GetOrCreateThreadData to guard against future reintroduction of multiple
collectors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace CrstLeafLock usage in AsyncContinuationsManager with a
dedicated CrstAsyncContinuations crst type that has proper lock
ordering (AcquiredBefore LeafLock).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 26, 2026 02:07
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

@am11
Copy link
Member

am11 commented Feb 26, 2026

Can this be replaced too:

GCX_COOP_NO_THREAD_BROKEN();
if so, after that we can delete GCX_COOP_NO_THREAD_BROKEN definition from src/coreclr/vm/util.hpp.

@AaronRobinsonMSFT
Copy link
Member Author

Can this be replaced too:

GCX_COOP_NO_THREAD_BROKEN();

if so, after that we can delete GCX_COOP_NO_THREAD_BROKEN definition from src/coreclr/vm/util.hpp.

Excellent observation, that is a great follow-up PR to verify this is still needed.

Remove the g_fEEStarted conditional that immediately freed old bucket
arrays during startup. Other threads (finalizer, debugger, tracing)
are created before g_fEEStarted is set, so the single-threaded
assumption was incorrect.

Now always queue old buckets via EBR deferred deletion and always
enter EBR critical regions, matching the safety guarantees that
HashMap provides for async mode.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@AaronRobinsonMSFT AaronRobinsonMSFT marked this pull request as ready for review February 26, 2026 20:27
Copilot AI review requested due to automatic review settings February 26, 2026 20:27
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

LGTM, assuming the tests are green

@AaronRobinsonMSFT AaronRobinsonMSFT merged commit 17ca03d into dotnet:main Feb 27, 2026
103 of 105 checks passed
@AaronRobinsonMSFT AaronRobinsonMSFT deleted the ebr-eehash branch February 27, 2026 01:48
@github-project-automation github-project-automation bot moved this to Done in AppModel Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants