Skip to content

Commit d29488f

Browse files
committed
Perform initial work in the job
Currently the first thing a reconciler after startup does is to sleep for a while then call initialProcess then start the processing loop (that sleeps again...). This now moves this initial work into the start job so we have a plain processing loop in the thread to make further improvements easier.
1 parent f41ea06 commit d29488f

File tree

2 files changed

+87
-78
lines changed

2 files changed

+87
-78
lines changed

bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/AbstractReconciler.java

Lines changed: 83 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ abstract public class AbstractReconciler implements IReconciler {
5555
/**
5656
* Background thread for the reconciling activity.
5757
*/
58-
class BackgroundThread extends Thread {
58+
class BackgroundWorker implements Runnable {
5959

6060
/** Has the reconciler been canceled. */
6161
private boolean fCanceled= false;
@@ -68,16 +68,14 @@ class BackgroundThread extends Thread {
6868

6969
private boolean fStarted;
7070

71-
/**
72-
* Creates a new background thread. The thread
73-
* runs with minimal priority.
74-
*
75-
* @param name the thread's name
76-
*/
77-
public BackgroundThread(String name) {
78-
super(name);
79-
setPriority(Thread.MIN_PRIORITY);
80-
setDaemon(true);
71+
private String fName;
72+
73+
private boolean fIsAlive;
74+
75+
private volatile Thread fThread;
76+
77+
public BackgroundWorker(String name) {
78+
fName= name;
8179
}
8280

8381
/**
@@ -172,74 +170,79 @@ public void reset() {
172170
*/
173171
@Override
174172
public void run() {
173+
try {
174+
while (!fCanceled) {
175175

176-
delay();
177-
178-
if (fCanceled)
179-
return;
180-
181-
initialProcess();
182-
183-
while (!fCanceled) {
184-
185-
delay();
186-
187-
if (fCanceled)
188-
break;
176+
delay();
189177

190-
if (!isDirty()) {
191-
waitFinish= false; //signalWaitForFinish() was called but nothing todo
192-
continue;
193-
}
178+
if (fCanceled)
179+
break;
194180

195-
synchronized (this) {
196-
if (fReset) {
197-
fReset= false;
181+
if (!isDirty()) {
182+
waitFinish= false; //signalWaitForFinish() was called but nothing todo
198183
continue;
199184
}
200-
}
201185

202-
DirtyRegion r= null;
203-
synchronized (fDirtyRegionQueue) {
204-
r= fDirtyRegionQueue.removeNextDirtyRegion();
205-
}
186+
synchronized (this) {
187+
if (fReset) {
188+
fReset= false;
189+
continue;
190+
}
191+
}
206192

207-
fIsActive= true;
193+
DirtyRegion r= null;
194+
synchronized (fDirtyRegionQueue) {
195+
r= fDirtyRegionQueue.removeNextDirtyRegion();
196+
}
208197

209-
fProgressMonitor.setCanceled(false);
198+
fIsActive= true;
210199

211-
process(r);
200+
fProgressMonitor.setCanceled(false);
212201

213-
synchronized (fDirtyRegionQueue) {
214-
if (0 == fDirtyRegionQueue.getSize()) {
215-
synchronized (this) {
216-
fIsDirty= fProgressMonitor.isCanceled();
202+
process(r);
203+
204+
synchronized (fDirtyRegionQueue) {
205+
if (fDirtyRegionQueue.isEmpty()) {
206+
synchronized (this) {
207+
fIsDirty= fProgressMonitor.isCanceled();
208+
}
209+
fDirtyRegionQueue.notifyAll();
217210
}
218-
fDirtyRegionQueue.notifyAll();
219211
}
212+
fIsActive= false;
220213
}
221-
222-
fIsActive= false;
214+
} finally {
215+
fIsAlive= false;
223216
}
224217
}
225218

219+
boolean isAlive() {
220+
return fIsAlive;
221+
}
222+
226223
public void startReconciling() {
227-
if (!isAlive()) {
228-
if (fStarted) {
229-
return;
230-
}
224+
if (!fStarted) {
225+
fIsAlive= true;
231226
fStarted= true;
232-
Job.createSystem("Delayed Reconciler startup", m -> { //$NON-NLS-1$
233-
try {
234-
start();
235-
return Status.OK_STATUS;
236-
} catch (IllegalThreadStateException e) {
237-
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=40549
238-
// This is the only instance where the thread is started; since
239-
// we checked that it is not alive, it must be dead already due
240-
// to a run-time exception or error. Exit.
227+
Job.createSystem("Delayed Reconciler startup for " + fName, m -> { //$NON-NLS-1$
228+
//Until we process some code from the job, the reconciler thread is the current thread
229+
fThread= Thread.currentThread();
230+
delay();
231+
if (fCanceled) {
232+
return Status.CANCEL_STATUS;
233+
}
234+
initialProcess();
235+
if (fCanceled) {
241236
return Status.CANCEL_STATUS;
242237
}
238+
Thread thread= new Thread(this);
239+
thread.setName(fName);
240+
thread.setPriority(Thread.MIN_PRIORITY);
241+
thread.setDaemon(true);
242+
//we will no longer process any code here, so hand over to the worker thread.
243+
fThread= thread;
244+
thread.start();
245+
return Status.OK_STATUS;
243246
}).schedule();
244247
} else {
245248
reset();
@@ -260,8 +263,8 @@ public void documentAboutToBeChanged(DocumentEvent e) {
260263
@Override
261264
public void documentChanged(DocumentEvent e) {
262265

263-
if (fThread.isActive() || !fThread.isDirty() && fThread.isAlive()) {
264-
if (!fIsAllowedToModifyDocument && Thread.currentThread() == fThread)
266+
if (fWorker.isActive() || !fWorker.isDirty() && fWorker.isAlive()) {
267+
if (!fIsAllowedToModifyDocument && isRunningInReconcilerThread())
265268
throw new UnsupportedOperationException("The reconciler thread is not allowed to modify the document"); //$NON-NLS-1$
266269
aboutToBeReconciledInternal();
267270
}
@@ -270,13 +273,13 @@ public void documentChanged(DocumentEvent e) {
270273
* The second OR condition handles the case when the document
271274
* gets changed while still inside initialProcess().
272275
*/
273-
if (fThread.isActive() || fThread.isDirty() && fThread.isAlive())
276+
if (fWorker.isActive() || fWorker.isDirty() && fWorker.isAlive())
274277
fProgressMonitor.setCanceled(true);
275278

276279
if (fIsIncrementalReconciler)
277280
createDirtyRegion(e);
278281

279-
fThread.reset();
282+
fWorker.reset();
280283

281284
}
282285

@@ -292,11 +295,11 @@ public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput
292295
synchronized (fDirtyRegionQueue) {
293296
fDirtyRegionQueue.purgeQueue();
294297
}
295-
if (fDocument != null && fDocument.getLength() > 0 && fThread.isDirty() && fThread.isAlive()) {
298+
if (fDocument != null && fDocument.getLength() > 0 && fWorker.isDirty() && fWorker.isAlive()) {
296299
DocumentEvent e= new DocumentEvent(fDocument, 0, fDocument.getLength(), ""); //$NON-NLS-1$
297300
createDirtyRegion(e);
298-
fThread.reset();
299-
fThread.suspendCallerWhileDirty();
301+
fWorker.reset();
302+
fWorker.suspendCallerWhileDirty();
300303
}
301304
}
302305

@@ -316,7 +319,7 @@ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
316319

317320
fDocument.addDocumentListener(this);
318321

319-
if (!fThread.isDirty())
322+
if (!fWorker.isDirty())
320323
aboutToBeReconciledInternal();
321324

322325
startReconciling();
@@ -326,7 +329,7 @@ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
326329
/** Queue to manage the changes applied to the text viewer. */
327330
private DirtyRegionQueue fDirtyRegionQueue;
328331
/** The background thread. */
329-
private BackgroundThread fThread;
332+
private BackgroundWorker fWorker;
330333
/** Internal document and text input listener. */
331334
private Listener fListener;
332335
/** The background thread delay. */
@@ -475,9 +478,9 @@ public void install(ITextViewer textViewer) {
475478
fViewer= textViewer;
476479

477480
synchronized (this) {
478-
if (fThread != null)
481+
if (fWorker != null)
479482
return;
480-
fThread= new BackgroundThread(getClass().getName());
483+
fWorker= new BackgroundWorker(getClass().getName());
481484
}
482485

483486
fDirtyRegionQueue= new DirtyRegionQueue();
@@ -511,8 +514,8 @@ public void uninstall() {
511514

512515
synchronized (this) {
513516
// http://dev.eclipse.org/bugs/show_bug.cgi?id=19135
514-
BackgroundThread bt= fThread;
515-
fThread= null;
517+
BackgroundWorker bt= fWorker;
518+
fWorker= null;
516519
bt.cancel();
517520
}
518521
}
@@ -618,10 +621,10 @@ protected void forceReconciling() {
618621

619622
if (fDocument != null) {
620623

621-
if (!fThread.isDirty()&& fThread.isAlive())
624+
if (!fWorker.isDirty()&& fWorker.isAlive())
622625
aboutToBeReconciledInternal();
623626

624-
if (fThread.isActive())
627+
if (fWorker.isActive())
625628
fProgressMonitor.setCanceled(true);
626629

627630
if (fIsIncrementalReconciler) {
@@ -638,10 +641,10 @@ protected void forceReconciling() {
638641
* Clients may extend this method.
639642
*/
640643
protected synchronized void startReconciling() {
641-
if (fThread == null)
644+
if (fWorker == null)
642645
return;
643646

644-
fThread.startReconciling();
647+
fWorker.startReconciling();
645648
}
646649

647650
/**
@@ -657,7 +660,9 @@ protected void reconcilerReset() {
657660
* @return <code>true</code> if running in this reconciler's background thread
658661
* @since 3.4
659662
*/
660-
protected boolean isRunningInReconcilerThread() {
661-
return Thread.currentThread() == fThread;
663+
protected synchronized boolean isRunningInReconcilerThread() {
664+
if (fWorker == null)
665+
return false;
666+
return Thread.currentThread() == fWorker.fThread;
662667
}
663668
}

bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/DirtyRegionQueue.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ public int getSize() {
8585
return fDirtyRegions.size();
8686
}
8787

88+
public boolean isEmpty() {
89+
return fDirtyRegions.isEmpty();
90+
}
91+
8892
/**
8993
* Throws away all entries in the queue.
9094
*/

0 commit comments

Comments
 (0)