Bug 574498 - [performance] reduce effective sleep in DecorationScheduler

by notifying when the pending jobs finished.

Change-Id: I33fc1a6d13d9194d5513a3e97db77e6ed56081eb
Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.ui/+/182538
Tested-by: Platform Bot <platform-bot@eclipse.org>
Reviewed-by: Mickael Istria <mistria@redhat.com>
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/decorators/DecorationScheduler.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/decorators/DecorationScheduler.java
index 5333abe..1e92c21 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/decorators/DecorationScheduler.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/decorators/DecorationScheduler.java
@@ -30,7 +30,9 @@
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
 import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
 import org.eclipse.jface.resource.ResourceManager;
 import org.eclipse.jface.viewers.DecorationContext;
 import org.eclipse.jface.viewers.IDecorationContext;
@@ -131,6 +133,30 @@
 
 	private Job decorationJob;
 
+	// Notifies about updateJob or clearJob finishing
+	private final class JobChangeListener extends JobChangeAdapter {
+
+		// is called after changeState(job, Job.NONE);
+		@Override
+		public void done(IJobChangeEvent event) {
+			synchronized (this) {
+				if (!updatesPending()) { // signal only if no more updates pending
+					this.notifyAll(); // also notify if nobody is waiting.
+				}
+			}
+		}
+
+		void sleep(long timeoutMillis) throws InterruptedException {
+			synchronized (this) {
+				if (updatesPending()) { // avoid wait if no updates pending
+					this.wait(timeoutMillis);
+				}
+			}
+		}
+	}
+
+	private final JobChangeListener jobFinishListener = new JobChangeListener();
+
 	private UIJob updateJob;
 
 	private Collection<ILabelProviderListener> removedListeners = Collections.synchronizedSet(new HashSet<>());
@@ -338,7 +364,7 @@
 				while (updatesPending()) {
 
 					try {
-						Thread.sleep(100);
+						jobFinishListener.sleep(100);
 					} catch (InterruptedException e) {
 						// Cancel and try again if there was an error
 						schedule();
@@ -468,7 +494,7 @@
 
 		};
 		clear.setSystem(true);
-
+		clear.addJobChangeListener(jobFinishListener);
 		return clear;
 	}
 
@@ -591,6 +617,7 @@
 		};
 
 		job.setSystem(true);
+		job.addJobChangeListener(jobFinishListener);
 		return job;
 	}