diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/AbstractReconciler.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/AbstractReconciler.java
index 511dd77305c..e4ad7855bf6 100644
--- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/AbstractReconciler.java
+++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/AbstractReconciler.java
@@ -16,6 +16,7 @@
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.text.DocumentEvent;
@@ -50,6 +51,203 @@
*/
abstract public class AbstractReconciler implements IReconciler {
+
+ /**
+ * Background thread for the reconciling activity.
+ */
+ class BackgroundThread extends Thread {
+
+ /** Has the reconciler been canceled. */
+ private boolean fCanceled= false;
+ /** Has the reconciler been reset. */
+ private boolean fReset= false;
+ /** Some changes need to be processed. */
+ private boolean fIsDirty= false;
+ /** Is a reconciling strategy active. */
+ private boolean fIsActive= false;
+
+ private boolean fStarted;
+
+ /**
+ * Creates a new background thread. The thread
+ * runs with minimal priority.
+ *
+ * @param name the thread's name
+ */
+ public BackgroundThread(String name) {
+ super(name);
+ setPriority(Thread.MIN_PRIORITY);
+ setDaemon(true);
+ }
+
+ /**
+ * Returns whether a reconciling strategy is active right now.
+ *
+ * @return true if a activity is active
+ */
+ public boolean isActive() {
+ return fIsActive;
+ }
+
+ /**
+ * Returns whether some changes need to be processed.
+ *
+ * @return true if changes wait to be processed
+ * @since 3.0
+ */
+ public synchronized boolean isDirty() {
+ return fIsDirty;
+ }
+
+ /**
+ * Cancels the background thread.
+ */
+ public void cancel() {
+ fCanceled= true;
+ IProgressMonitor pm= fProgressMonitor;
+ if (pm != null)
+ pm.setCanceled(true);
+ synchronized (fDirtyRegionQueue) {
+ fDirtyRegionQueue.notifyAll();
+ }
+ }
+
+ /**
+ * Suspends the caller of this method until this background thread has
+ * emptied the dirty region queue.
+ */
+ public void suspendCallerWhileDirty() {
+ AbstractReconciler.this.signalWaitForFinish();
+ boolean isDirty;
+ do {
+ synchronized (fDirtyRegionQueue) {
+ isDirty= fDirtyRegionQueue.getSize() > 0;
+ if (isDirty) {
+ try {
+ fDirtyRegionQueue.wait();
+ } catch (InterruptedException x) {
+ }
+ }
+ }
+ } while (isDirty);
+ }
+
+ /**
+ * Reset the background thread as the text viewer has been changed,
+ */
+ public void reset() {
+
+ if (fDelay > 0) {
+
+ synchronized (this) {
+ fIsDirty= true;
+ fReset= true;
+ }
+ synchronized (fDirtyRegionQueue) {
+ fDirtyRegionQueue.notifyAll(); // wake up wait(fDelay);
+ }
+
+ } else {
+
+ synchronized (this) {
+ fIsDirty= true;
+ }
+
+ synchronized (fDirtyRegionQueue) {
+ fDirtyRegionQueue.notifyAll();
+ }
+ }
+
+ informNotFinished();
+ reconcilerReset();
+ }
+
+ /**
+ * The background activity. Waits until there is something in the
+ * queue managing the changes that have been applied to the text viewer.
+ * Removes the first change from the queue and process it.
+ *
+ * Calls {@link AbstractReconciler#initialProcess()} on entrance. + *
+ */ + @Override + public void run() { + + delay(); + + if (fCanceled) + return; + + initialProcess(); + + while (!fCanceled) { + + delay(); + + if (fCanceled) + break; + + if (!isDirty()) { + waitFinish= false; //signalWaitForFinish() was called but nothing todo + continue; + } + + synchronized (this) { + if (fReset) { + fReset= false; + continue; + } + } + + DirtyRegion r= null; + synchronized (fDirtyRegionQueue) { + r= fDirtyRegionQueue.removeNextDirtyRegion(); + } + + fIsActive= true; + + fProgressMonitor.setCanceled(false); + + process(r); + + synchronized (fDirtyRegionQueue) { + if (0 == fDirtyRegionQueue.getSize()) { + synchronized (this) { + fIsDirty= fProgressMonitor.isCanceled(); + } + fDirtyRegionQueue.notifyAll(); + } + } + + fIsActive= false; + } + } + + public void startReconciling() { + if (!isAlive()) { + if (fStarted) { + return; + } + fStarted= true; + Job.createSystem("Delayed Reconciler startup", m -> { //$NON-NLS-1$ + try { + start(); + return Status.OK_STATUS; + } catch (IllegalThreadStateException e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=40549 + // This is the only instance where the thread is started; since + // we checked that it is not alive, it must be dead already due + // to a run-time exception or error. Exit. + return Status.CANCEL_STATUS; + } + }).schedule(); + } else { + reset(); + } + + } + } + /** * Internal document listener and text input listener. */ @@ -63,7 +261,7 @@ public void documentAboutToBeChanged(DocumentEvent e) { public void documentChanged(DocumentEvent e) { if (fThread.isActive() || !fThread.isDirty() && fThread.isAlive()) { - if (!fIsAllowedToModifyDocument && isRunningInReconcilerThread()) + if (!fIsAllowedToModifyDocument && Thread.currentThread() == fThread) throw new UnsupportedOperationException("The reconciler thread is not allowed to modify the document"); //$NON-NLS-1$ aboutToBeReconciledInternal(); } @@ -126,14 +324,13 @@ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { } /** Queue to manage the changes applied to the text viewer. */ - DirtyRegionQueue fDirtyRegionQueue; + private DirtyRegionQueue fDirtyRegionQueue; /** The background thread. */ - private ReconcilerJob fThread; + private BackgroundThread fThread; /** Internal document and text input listener. */ private Listener fListener; - /** The background thread delay. */ - int fDelay= 500; + private int fDelay= 500; /** Signal that the the background thread should not delay. */ volatile boolean waitFinish; /** Are there incremental reconciling strategies? */ @@ -280,7 +477,7 @@ public void install(ITextViewer textViewer) { synchronized (this) { if (fThread != null) return; - fThread= new ReconcilerJob(getClass().getName(), this); + fThread= new BackgroundThread(getClass().getName()); } fDirtyRegionQueue= new DirtyRegionQueue(); @@ -314,9 +511,9 @@ public void uninstall() { synchronized (this) { // http://dev.eclipse.org/bugs/show_bug.cgi?id=19135 - ReconcilerJob bt= fThread; + BackgroundThread bt= fThread; fThread= null; - bt.doCancel(); + bt.cancel(); } } } @@ -383,7 +580,7 @@ public void signalWaitForFinish() { } } - void informNotFinished() { + private void informNotFinished() { waitFinish= false; aboutToWork(); } @@ -394,7 +591,7 @@ private void aboutToBeReconciledInternal() { } - void delay() { + private void delay() { synchronized (fDirtyRegionQueue) { if (waitFinish) { return; // do not delay when waiting; @@ -444,11 +641,7 @@ protected synchronized void startReconciling() { if (fThread == null) return; - if (!fThread.isAlive()) { - fThread.start(); - } else { - fThread.reset(); - } + fThread.startReconciling(); } /** @@ -464,10 +657,7 @@ protected void reconcilerReset() { * @returntrue if running in this reconciler's background thread
* @since 3.4
*/
- protected synchronized boolean isRunningInReconcilerThread() {
- if (fThread == null) {
- return false;
- }
- return Job.getJobManager().currentJob() == fThread;
+ protected boolean isRunningInReconcilerThread() {
+ return Thread.currentThread() == fThread;
}
-}
\ No newline at end of file
+}
diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/ReconcilerJob.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/ReconcilerJob.java
deleted file mode 100644
index f9c7db1e4bd..00000000000
--- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/ReconcilerJob.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2025 IBM Corporation and others.
- *
- * This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License 2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
- * Christoph Läubrich - extract into own class
- *******************************************************************************/
-package org.eclipse.jface.text.reconciler;
-
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
-
-/**
- * Background thread for the reconciling activity.
- */
-class ReconcilerJob extends Job {
-
- /** Has the reconciler been canceled. */
- private boolean fCanceled= false;
-
- /** Has the reconciler been reset. */
- private boolean fReset= false;
-
- /** Some changes need to be processed. */
- private boolean fIsDirty= false;
-
- /** Is a reconciling strategy active. */
- private boolean fIsActive= false;
-
- private volatile boolean fIsAlive;
-
- private boolean started;
-
- private AbstractReconciler fReconciler;
-
- /**
- * Creates a new background thread. The thread runs with minimal priority.
- *
- * @param name the thread's name
- */
- public ReconcilerJob(String name, AbstractReconciler reconciler) {
- super(name);
- fReconciler= reconciler;
- setPriority(Job.DECORATE);
- setSystem(true);
- }
-
- /**
- * Returns whether a reconciling strategy is active right now.
- *
- * @return true if a activity is active
- */
- public boolean isActive() {
- return fIsActive;
- }
-
- /**
- * Returns whether some changes need to be processed.
- *
- * @return true if changes wait to be processed
- * @since 3.0
- */
- public synchronized boolean isDirty() {
- return fIsDirty;
- }
-
- /**
- * Cancels the background thread.
- */
- public void doCancel() {
- fCanceled= true;
- IProgressMonitor pm= fReconciler.getProgressMonitor();
- if (pm != null)
- pm.setCanceled(true);
- synchronized (fReconciler.fDirtyRegionQueue) {
- fReconciler.fDirtyRegionQueue.notifyAll();
- }
- }
-
- /**
- * Suspends the caller of this method until this background thread has emptied the dirty region
- * queue.
- */
- public void suspendCallerWhileDirty() {
- fReconciler.signalWaitForFinish();
- boolean isDirty;
- do {
- synchronized (fReconciler.fDirtyRegionQueue) {
- isDirty= fReconciler.fDirtyRegionQueue.getSize() > 0;
- if (isDirty) {
- try {
- fReconciler.fDirtyRegionQueue.wait();
- } catch (InterruptedException x) {
- }
- }
- }
- } while (isDirty);
- }
-
- /**
- * Reset the background thread as the text viewer has been changed,
- */
- public void reset() {
-
- if (fReconciler.fDelay > 0) {
-
- synchronized (this) {
- fIsDirty= true;
- fReset= true;
- }
- synchronized (fReconciler.fDirtyRegionQueue) {
- fReconciler.fDirtyRegionQueue.notifyAll(); // wake up wait(fDelay);
- }
-
- } else {
-
- synchronized (this) {
- fIsDirty= true;
- }
-
- synchronized (fReconciler.fDirtyRegionQueue) {
- fReconciler.fDirtyRegionQueue.notifyAll();
- }
- }
- synchronized (this) {
- started= false;
- }
- fReconciler.informNotFinished();
- fReconciler.reconcilerReset();
- }
-
- /**
- * The background activity. Waits until there is something in the queue managing the changes
- * that have been applied to the text viewer. Removes the first change from the queue and
- * process it.
- * - * Calls {@link AbstractReconciler#initialProcess()} on entrance. - *
- */ - @Override - public IStatus run(IProgressMonitor monitor) { - fIsAlive= true; - fReconciler.delay(); - - if (fCanceled) - return Status.CANCEL_STATUS; - - fReconciler.initialProcess(); - - while (!fCanceled) { - - fReconciler.delay(); - - if (fCanceled) - break; - - if (!isDirty()) { - fReconciler.waitFinish= false; //signalWaitForFinish() was called but nothing todo - continue; - } - - synchronized (this) { - if (fReset) { - fReset= false; - continue; - } - } - - DirtyRegion r= null; - synchronized (fReconciler.fDirtyRegionQueue) { - r= fReconciler.fDirtyRegionQueue.removeNextDirtyRegion(); - } - - fIsActive= true; - - fReconciler.getProgressMonitor().setCanceled(false); - - fReconciler.process(r); - - synchronized (fReconciler.fDirtyRegionQueue) { - if (0 == fReconciler.fDirtyRegionQueue.getSize()) { - synchronized (this) { - fIsDirty= fReconciler.getProgressMonitor().isCanceled(); - } - fReconciler.fDirtyRegionQueue.notifyAll(); - } - } - - fIsActive= false; - } - fIsAlive= false; - return Status.OK_STATUS; - } - - public boolean isAlive() { - return fIsAlive; - } - - public synchronized void start() { - if (!started) { - started= true; - schedule(); - } - } - - @Override - public boolean belongsTo(Object family) { - return family == fReconciler.getTextViewer() || AbstractReconciler.class == family; - } - -}