Bug 560274 - Race condition when updating debug toolbar button states

This change adjusts the scheduling rule when updating toolbar command
enablement via
"org.eclipse.debug.internal.core.commands.ForEachCommand", e.g. the
suspend toolbar enabled button state.

The new rule is exclusive per command, as opposed to exclusive per
selection type. I.e. before, debug target updates were exclusive, stack
frame updates were exclusive, etc. Now, disconnect command updates are
exclusive, suspend command updates are exclusive, etc.

Change-Id: Ia22232b0a55c3aba429bc980ec5a26eb238afd44
Signed-off-by: Simeon Andreev <simeon.danailov.andreev@gmail.com>
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/commands/ForEachCommand.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/commands/ForEachCommand.java
index a1b418f..e222a72 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/commands/ForEachCommand.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/commands/ForEachCommand.java
@@ -15,8 +15,10 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.debug.core.IRequest;
 import org.eclipse.debug.core.commands.AbstractDebugCommand;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
 import org.eclipse.debug.core.commands.IEnabledStateRequest;
 
 /**
@@ -26,6 +28,8 @@
  */
 public abstract class ForEachCommand extends AbstractDebugCommand {
 
+	private final ExclusiveRule exclusiveRule = new ExclusiveRule();
+
 	@Override
 	protected void doExecute(Object[] targets, IProgressMonitor monitor, IRequest request) throws CoreException {
 		for (Object target : targets) {
@@ -49,4 +53,28 @@
 
 	protected abstract boolean isExecutable(Object target);
 
+	/*
+	 * Do not allow parallel update requests for the same command, since those
+	 * can result in race conditions, where one selected element enables a
+	 * command and another selected element disables the command. Depending on
+	 * which request is processed first, the debug command could end up with the
+	 * wrong enabled state. See bug 560274.
+	 */
+	@Override
+	protected ISchedulingRule getEnabledStateSchedulingRule(IDebugCommandRequest request) {
+		return exclusiveRule;
+	}
+
+	static class ExclusiveRule implements ISchedulingRule {
+
+		@Override
+		public boolean contains(ISchedulingRule rule) {
+			return rule == this;
+		}
+
+		@Override
+		public boolean isConflicting(ISchedulingRule rule) {
+			return contains(rule);
+		}
+	}
 }