16
16
import org .eclipse .core .runtime .Assert ;
17
17
import org .eclipse .core .runtime .IProgressMonitor ;
18
18
import org .eclipse .core .runtime .NullProgressMonitor ;
19
+ import org .eclipse .core .runtime .Status ;
19
20
import org .eclipse .core .runtime .jobs .Job ;
20
21
21
22
import org .eclipse .jface .text .DocumentEvent ;
50
51
*/
51
52
abstract public class AbstractReconciler implements IReconciler {
52
53
54
+
55
+ /**
56
+ * Background thread for the reconciling activity.
57
+ */
58
+ class BackgroundThread extends Thread {
59
+
60
+ /** Has the reconciler been canceled. */
61
+ private boolean fCanceled = false ;
62
+ /** Has the reconciler been reset. */
63
+ private boolean fReset = false ;
64
+ /** Some changes need to be processed. */
65
+ private boolean fIsDirty = false ;
66
+ /** Is a reconciling strategy active. */
67
+ private boolean fIsActive = false ;
68
+
69
+ private boolean fStarted ;
70
+
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 );
81
+ }
82
+
83
+ /**
84
+ * Returns whether a reconciling strategy is active right now.
85
+ *
86
+ * @return <code>true</code> if a activity is active
87
+ */
88
+ public boolean isActive () {
89
+ return fIsActive ;
90
+ }
91
+
92
+ /**
93
+ * Returns whether some changes need to be processed.
94
+ *
95
+ * @return <code>true</code> if changes wait to be processed
96
+ * @since 3.0
97
+ */
98
+ public synchronized boolean isDirty () {
99
+ return fIsDirty ;
100
+ }
101
+
102
+ /**
103
+ * Cancels the background thread.
104
+ */
105
+ public void cancel () {
106
+ fCanceled = true ;
107
+ IProgressMonitor pm = fProgressMonitor ;
108
+ if (pm != null )
109
+ pm .setCanceled (true );
110
+ synchronized (fDirtyRegionQueue ) {
111
+ fDirtyRegionQueue .notifyAll ();
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Suspends the caller of this method until this background thread has
117
+ * emptied the dirty region queue.
118
+ */
119
+ public void suspendCallerWhileDirty () {
120
+ AbstractReconciler .this .signalWaitForFinish ();
121
+ boolean isDirty ;
122
+ do {
123
+ synchronized (fDirtyRegionQueue ) {
124
+ isDirty = fDirtyRegionQueue .getSize () > 0 ;
125
+ if (isDirty ) {
126
+ try {
127
+ fDirtyRegionQueue .wait ();
128
+ } catch (InterruptedException x ) {
129
+ }
130
+ }
131
+ }
132
+ } while (isDirty );
133
+ }
134
+
135
+ /**
136
+ * Reset the background thread as the text viewer has been changed,
137
+ */
138
+ public void reset () {
139
+
140
+ if (fDelay > 0 ) {
141
+
142
+ synchronized (this ) {
143
+ fIsDirty = true ;
144
+ fReset = true ;
145
+ }
146
+ synchronized (fDirtyRegionQueue ) {
147
+ fDirtyRegionQueue .notifyAll (); // wake up wait(fDelay);
148
+ }
149
+
150
+ } else {
151
+
152
+ synchronized (this ) {
153
+ fIsDirty = true ;
154
+ }
155
+
156
+ synchronized (fDirtyRegionQueue ) {
157
+ fDirtyRegionQueue .notifyAll ();
158
+ }
159
+ }
160
+
161
+ informNotFinished ();
162
+ reconcilerReset ();
163
+ }
164
+
165
+ /**
166
+ * The background activity. Waits until there is something in the
167
+ * queue managing the changes that have been applied to the text viewer.
168
+ * Removes the first change from the queue and process it.
169
+ * <p>
170
+ * Calls {@link AbstractReconciler#initialProcess()} on entrance.
171
+ * </p>
172
+ */
173
+ @ Override
174
+ public void run () {
175
+
176
+ delay ();
177
+
178
+ if (fCanceled )
179
+ return ;
180
+
181
+ initialProcess ();
182
+
183
+ while (!fCanceled ) {
184
+
185
+ delay ();
186
+
187
+ if (fCanceled )
188
+ break ;
189
+
190
+ if (!isDirty ()) {
191
+ waitFinish = false ; //signalWaitForFinish() was called but nothing todo
192
+ continue ;
193
+ }
194
+
195
+ synchronized (this ) {
196
+ if (fReset ) {
197
+ fReset = false ;
198
+ continue ;
199
+ }
200
+ }
201
+
202
+ DirtyRegion r = null ;
203
+ synchronized (fDirtyRegionQueue ) {
204
+ r = fDirtyRegionQueue .removeNextDirtyRegion ();
205
+ }
206
+
207
+ fIsActive = true ;
208
+
209
+ fProgressMonitor .setCanceled (false );
210
+
211
+ process (r );
212
+
213
+ synchronized (fDirtyRegionQueue ) {
214
+ if (0 == fDirtyRegionQueue .getSize ()) {
215
+ synchronized (this ) {
216
+ fIsDirty = fProgressMonitor .isCanceled ();
217
+ }
218
+ fDirtyRegionQueue .notifyAll ();
219
+ }
220
+ }
221
+
222
+ fIsActive = false ;
223
+ }
224
+ }
225
+
226
+ public void startReconciling () {
227
+ if (!isAlive ()) {
228
+ if (fStarted ) {
229
+ return ;
230
+ }
231
+ 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.
241
+ return Status .CANCEL_STATUS ;
242
+ }
243
+ }).schedule ();
244
+ } else {
245
+ reset ();
246
+ }
247
+
248
+ }
249
+ }
250
+
53
251
/**
54
252
* Internal document listener and text input listener.
55
253
*/
@@ -63,7 +261,7 @@ public void documentAboutToBeChanged(DocumentEvent e) {
63
261
public void documentChanged (DocumentEvent e ) {
64
262
65
263
if (fThread .isActive () || !fThread .isDirty () && fThread .isAlive ()) {
66
- if (!fIsAllowedToModifyDocument && isRunningInReconcilerThread () )
264
+ if (!fIsAllowedToModifyDocument && Thread . currentThread () == fThread )
67
265
throw new UnsupportedOperationException ("The reconciler thread is not allowed to modify the document" ); //$NON-NLS-1$
68
266
aboutToBeReconciledInternal ();
69
267
}
@@ -126,14 +324,13 @@ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
126
324
}
127
325
128
326
/** Queue to manage the changes applied to the text viewer. */
129
- DirtyRegionQueue fDirtyRegionQueue ;
327
+ private DirtyRegionQueue fDirtyRegionQueue ;
130
328
/** The background thread. */
131
- private ReconcilerJob fThread ;
329
+ private BackgroundThread fThread ;
132
330
/** Internal document and text input listener. */
133
331
private Listener fListener ;
134
-
135
332
/** The background thread delay. */
136
- int fDelay = 500 ;
333
+ private int fDelay = 500 ;
137
334
/** Signal that the the background thread should not delay. */
138
335
volatile boolean waitFinish ;
139
336
/** Are there incremental reconciling strategies? */
@@ -280,7 +477,7 @@ public void install(ITextViewer textViewer) {
280
477
synchronized (this ) {
281
478
if (fThread != null )
282
479
return ;
283
- fThread = new ReconcilerJob (getClass ().getName (), this );
480
+ fThread = new BackgroundThread (getClass ().getName ());
284
481
}
285
482
286
483
fDirtyRegionQueue = new DirtyRegionQueue ();
@@ -314,9 +511,9 @@ public void uninstall() {
314
511
315
512
synchronized (this ) {
316
513
// http://dev.eclipse.org/bugs/show_bug.cgi?id=19135
317
- ReconcilerJob bt = fThread ;
514
+ BackgroundThread bt = fThread ;
318
515
fThread = null ;
319
- bt .doCancel ();
516
+ bt .cancel ();
320
517
}
321
518
}
322
519
}
@@ -383,7 +580,7 @@ public void signalWaitForFinish() {
383
580
}
384
581
}
385
582
386
- void informNotFinished () {
583
+ private void informNotFinished () {
387
584
waitFinish = false ;
388
585
aboutToWork ();
389
586
}
@@ -394,7 +591,7 @@ private void aboutToBeReconciledInternal() {
394
591
}
395
592
396
593
397
- void delay () {
594
+ private void delay () {
398
595
synchronized (fDirtyRegionQueue ) {
399
596
if (waitFinish ) {
400
597
return ; // do not delay when waiting;
@@ -444,11 +641,7 @@ protected synchronized void startReconciling() {
444
641
if (fThread == null )
445
642
return ;
446
643
447
- if (!fThread .isAlive ()) {
448
- fThread .start ();
449
- } else {
450
- fThread .reset ();
451
- }
644
+ fThread .startReconciling ();
452
645
}
453
646
454
647
/**
@@ -464,10 +657,7 @@ protected void reconcilerReset() {
464
657
* @return <code>true</code> if running in this reconciler's background thread
465
658
* @since 3.4
466
659
*/
467
- protected synchronized boolean isRunningInReconcilerThread () {
468
- if (fThread == null ) {
469
- return false ;
470
- }
471
- return Job .getJobManager ().currentJob () == fThread ;
660
+ protected boolean isRunningInReconcilerThread () {
661
+ return Thread .currentThread () == fThread ;
472
662
}
473
- }
663
+ }
0 commit comments