Skip to content

Fix race condition in CleanupAddon.subscribeRenderingChanged#3725

Draft
vogella wants to merge 2 commits intoeclipse-platform:masterfrom
vogella:fix-cleanup-addon-race-condition
Draft

Fix race condition in CleanupAddon.subscribeRenderingChanged#3725
vogella wants to merge 2 commits intoeclipse-platform:masterfrom
vogella:fix-cleanup-addon-race-condition

Conversation

@vogella
Copy link
Contributor

@vogella vogella commented Feb 4, 2026

The test ensureCleanUpAddonCleansUp was failing intermittently because CleanupAddon deferred container cleanup via Display.asyncExec(), creating a race condition where event loop pumping during part activation could interfere with async cleanup tasks.

Root cause analysis:

  • When hidePart() is called on parts with REMOVE_ON_HIDE_TAG, it triggers synchronous EMF model change events via UIEventPublisher
  • Event delivery is fully synchronous: EventBroker.send() ->
    EventAdmin.sendEvent() -> Display.syncExec() -> handler execution
  • The subscribeRenderingChanged handler detected visCount==0 but deferred cleanup via asyncExec (line 352)
  • Meanwhile, activate() calls during hidePart() pumped the event loop (via focusGui/SWT focus handling), potentially consuming queued asyncExecs before they could observe the final state
  • This created timing-dependent behavior where cleanup could be skipped

Fix:

  • Remove asyncExec wrapper from subscribeRenderingChanged's visCount==0 path
  • Since event delivery is synchronous, visCount already reflects the actual state at event time - no need to defer and re-check
  • Container is now hidden immediately when last renderable child becomes non-renderable, before any event loop pumping can interfere
  • Update test to use simple spinEventLoop + assertFalse instead of 30-second waitForCondition, as cleanup is now synchronous

This fixes the flaky test that failed ~1-3% of the time even with the 30-second timeout. The subscribeTopicChildren handler still uses asyncExec for children removal/sash unwrapping, but toBeRendered cleanup is now deterministic.

Fixes #3581

@github-actions
Copy link
Contributor

github-actions bot commented Feb 4, 2026

Test Results

 3 024 files  + 9   3 024 suites  +9   2h 5m 40s ⏱️ + 1m 27s
 8 234 tests ± 0   7 985 ✅ ± 0  248 💤 ±0  1 ❌ ±0 
23 526 runs  +26  22 734 ✅ +23  791 💤 +3  1 ❌ ±0 

For more details on these failures, see this check.

Results for commit d5fa691. ± Comparison against base commit e6d3cbf.

♻️ This comment has been updated with latest results.

@vogella
Copy link
Contributor Author

vogella commented Feb 4, 2026

AFAICS this is a save change (famous last words) and should finally fix our forever flaky cleanup race condition revealed in the cleanup test.

@vogella
Copy link
Contributor Author

vogella commented Feb 4, 2026

I suggest to wait for the beginn of the next release developement for this one.

@vogella vogella marked this pull request as draft February 4, 2026 13:27
@vogella vogella force-pushed the fix-cleanup-addon-race-condition branch from aa9e3b7 to 0b45f54 Compare February 13, 2026 09:50
The test ensureCleanUpAddonCleansUp was failing intermittently because
CleanupAddon deferred container cleanup via Display.asyncExec(), creating
a race condition where event loop pumping during part activation could
interfere with async cleanup tasks.

Root cause analysis:
- When hidePart() is called on parts with REMOVE_ON_HIDE_TAG, it triggers
  synchronous EMF model change events via UIEventPublisher
- Event delivery is fully synchronous: EventBroker.send() ->
  EventAdmin.sendEvent() -> Display.syncExec() -> handler execution
- The subscribeRenderingChanged handler detected visCount==0 but deferred
  cleanup via asyncExec (line 352)
- Meanwhile, activate() calls during hidePart() pumped the event loop
  (via focusGui/SWT focus handling), potentially consuming queued asyncExecs
  before they could observe the final state
- This created timing-dependent behavior where cleanup could be skipped

Fix:
- Remove asyncExec wrapper from subscribeRenderingChanged's visCount==0 path
- Since event delivery is synchronous, visCount already reflects the actual
  state at event time - no need to defer and re-check
- Container is now hidden immediately when last renderable child becomes
  non-renderable, before any event loop pumping can interfere
- Update test to use simple spinEventLoop + assertFalse instead of
  30-second waitForCondition, as cleanup is now synchronous

This fixes the flaky test that failed ~1-3% of the time even with the
30-second timeout. The subscribeTopicChildren handler still uses asyncExec
for children removal/sash unwrapping, but toBeRendered cleanup is now
deterministic.

Fixes eclipse-platform#3581

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@vogella vogella force-pushed the fix-cleanup-addon-race-condition branch from 0b45f54 to 9b6c852 Compare March 1, 2026 11:35
@eclipse-platform-bot
Copy link
Contributor

This pull request changes some projects for the first time in this development cycle.
Therefore the following files need a version increment:

bundles/org.eclipse.e4.ui.workbench.addons.swt/META-INF/MANIFEST.MF
tests/org.eclipse.e4.ui.tests/META-INF/MANIFEST.MF

An additional commit containing all the necessary changes was pushed to the top of this PR's branch. To obtain these changes (for example if you want to push more changes) either fetch from your fork or apply the git patch.

Git patch
From a4fa115510c6893d007bf618b9998f3bfcdd7213 Mon Sep 17 00:00:00 2001
From: Eclipse Platform Bot <platform-bot@eclipse.org>
Date: Sun, 1 Mar 2026 11:41:42 +0000
Subject: [PATCH] Version bump(s) for 4.40 stream


diff --git a/bundles/org.eclipse.e4.ui.workbench.addons.swt/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.workbench.addons.swt/META-INF/MANIFEST.MF
index b671e2de07..b01ce42504 100644
--- a/bundles/org.eclipse.e4.ui.workbench.addons.swt/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.ui.workbench.addons.swt/META-INF/MANIFEST.MF
@@ -1,7 +1,7 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-SymbolicName: org.eclipse.e4.ui.workbench.addons.swt;singleton:=true
-Bundle-Version: 1.6.0.qualifier
+Bundle-Version: 1.6.100.qualifier
 Bundle-Name: %pluginName
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/tests/org.eclipse.e4.ui.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.e4.ui.tests/META-INF/MANIFEST.MF
index ca9302d776..025940a11e 100644
--- a/tests/org.eclipse.e4.ui.tests/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.e4.ui.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.e4.ui.tests;singleton:=true
-Bundle-Version: 0.16.0.qualifier
+Bundle-Version: 0.16.100.qualifier
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
 Require-Bundle: org.eclipse.emf.ecore.xmi;bundle-version="2.4.0",
-- 
2.53.0

Further information are available in Common Build Issues - Missing version increments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PartRenderingEngineTests.ensureCleanUpAddonCleansUp still fails randomly

2 participants