Commit 334254f
committed
Fix race condition in AbstractReconciler.reset() event ordering
In BackgroundWorker.reset(), reconcilerReset() was called after
fIsDirty was set to true and after fDirtyRegionQueue.notifyAll() and
informNotFinished(). This created two race windows:
1. aboutToBeReconciledInternal() (called before reset() in both
documentChanged and inputDocumentChanged) triggers
signalWaitForFinish() which wakes the background thread via
notifyAll(). The background thread could then see fIsDirty=true
(set at the start of reset()), consume the fReset flag, loop back,
skip delay (waitFinish=true), and reach process() — all before the
main thread reached reconcilerReset().
2. Within reset() itself, notifyAll() and informNotFinished() (which
also triggers signalWaitForFinish → notifyAll) were called before
reconcilerReset(), providing additional wake-up points for the
background thread.
The fix moves reconcilerReset() to the very beginning of reset(),
before fIsDirty is set to true. This way, even if the background
thread is already awake from an earlier notification, it cannot find
work to do (isDirty() returns false) and blocks in delay() until after
reconcilerReset() completes and the state flags are set.
The reordered reset() is now:
1. reconcilerReset() — hook runs while isDirty is still false
2. Set state flags (fIsDirty, fReset) in synchronized block
3. informNotFinished() — may wake background thread
4. fDirtyRegionQueue.notifyAll() — wakes background thread
This guarantees the reconcilerReset hook completes before the
background thread can proceed to process().
User-visible impact: The AbstractReconciler drives background
processing in text editors (syntax validation, spell checking,
error/warning markers, code analysis). The race condition occurs when
the document changes or is replaced (e.g., switching files, reverting).
Without the reset happening first, process() can run with stale state,
causing brief flickers of incorrect error markers or squiggles from
the previous document on the new content. Being a race condition, this
is intermittent and self-corrects on the next reconciling pass.
Test coverage: Added ReconcilerResetOrderingTest which extends
FastAbstractReconcilerTest with a 50ms delay before logging
reconcilerReset. This widens the race window so that without the fix,
the background thread deterministically reaches process() before the
reset hook logs — causing testReplacingDocumentWhenClean and
testDirtyingWhenClean to always fail. With the fix, all tests pass
because the background thread cannot find work (isDirty=false) during
the delay. The full reconciler test suite (AbstractReconcilerTest +
FastAbstractReconcilerTest + ReconcilerResetOrderingTest, 21 tests)
covers reset() through all code paths.
See #27081 parent fa50c5b commit 334254f
4 files changed
Lines changed: 53 additions & 8 deletions
File tree
- bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler
- tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests
- reconciler
Lines changed: 6 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
140 | 140 | | |
141 | 141 | | |
142 | 142 | | |
| 143 | + | |
| 144 | + | |
143 | 145 | | |
144 | 146 | | |
145 | 147 | | |
146 | 148 | | |
147 | 149 | | |
148 | 150 | | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | 151 | | |
153 | 152 | | |
154 | 153 | | |
155 | 154 | | |
156 | 155 | | |
157 | 156 | | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | 157 | | |
163 | 158 | | |
164 | 159 | | |
165 | | - | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
166 | 164 | | |
167 | 165 | | |
168 | 166 | | |
| |||
Lines changed: 2 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
29 | 30 | | |
30 | 31 | | |
31 | 32 | | |
| |||
61 | 62 | | |
62 | 63 | | |
63 | 64 | | |
| 65 | + | |
64 | 66 | | |
65 | 67 | | |
66 | 68 | | |
| |||
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
173 | 173 | | |
174 | 174 | | |
175 | 175 | | |
| 176 | + | |
176 | 177 | | |
177 | 178 | | |
178 | 179 | | |
| |||
202 | 203 | | |
203 | 204 | | |
204 | 205 | | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
205 | 210 | | |
206 | 211 | | |
207 | 212 | | |
| |||
Lines changed: 40 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
0 commit comments