Bug 183286 JobManager can get into a state where same job is running in two threads at once
diff --git a/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/InternalJob.java b/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/InternalJob.java
index 684f83f..4c9bdc5 100644
--- a/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/InternalJob.java
+++ b/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/InternalJob.java
@@ -42,6 +42,11 @@
 	private static final int M_STATE = 0xFF;
 	private static final int M_SYSTEM = 0x0100;
 	private static final int M_USER = 0x0200;
+	
+	/*
+	 * flag on a job indicating that it was about to run, but has been canceled
+	 */
+	private static final int M_ABOUT_TO_RUN_CANCELED = 0x0400;
 
 	protected static final JobManager manager = JobManager.getInstance();
 	private static int nextJobNumber = 0;
@@ -268,6 +273,13 @@
 		flags = (flags & ~M_STATE) | i;
 	}
 
+	/**
+	 * Returns whether this job was canceled when it was about to run
+	 */
+	final boolean isAboutToRunCanceled(){
+		return (flags & M_ABOUT_TO_RUN_CANCELED) != 0;
+	}
+
 	/* (non-Javadoc)
 	 * @see Job#isBlocking()
 	 */
@@ -355,6 +367,14 @@
 		if (shouldSchedule())
 			manager.schedule(this, delay, false);
 	}
+	
+	/**
+	 * Sets whether this job was canceled when it was about to run
+	 */
+	final void setAboutToRunCanceled(boolean value) {
+		flags = value ? flags | M_ABOUT_TO_RUN_CANCELED : flags & ~M_ABOUT_TO_RUN_CANCELED;
+		
+	}
 
 	/* (non-Javadoc)
 	 * @see Job#setName(String)
diff --git a/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java b/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java
index 5ccaeb5..3ba75ef 100644
--- a/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java
+++ b/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java
@@ -57,7 +57,6 @@
 	static boolean DEBUG_TIMING = false;
 	static boolean DEBUG_SHUTDOWN = false;
 	private static DateFormat DEBUG_FORMAT;
-	private static final IProgressMonitor NULL_MONITOR = new NullProgressMonitor();
 
 	/**
 	 * The singleton job manager instance. It must be a singleton because
@@ -241,7 +240,9 @@
 						monitor = job.getProgressMonitor();
 						break;
 					}
-					//fall through for ABOUT_TO_RUN case
+					//signal that the job should be canceled before it gets a chance to run
+					job.setAboutToRunCanceled(true);
+					return true;
 				default :
 					changeState(job, Job.NONE);
 			}
@@ -538,7 +539,7 @@
 			if (JobManager.DEBUG && notify)
 				JobManager.debug("Ending job: " + job); //$NON-NLS-1$
 			job.setResult(result);
-			job.setProgressMonitor(NULL_MONITOR);
+			job.setProgressMonitor(null);
 			job.setThread(null);
 			rescheduleDelay = job.getStartTime();
 			changeState(job, Job.NONE);
@@ -1125,10 +1126,15 @@
 				synchronized (lock) {
 					if (job.getState() == Job.RUNNING) {
 						InternalJob internal = job;
-						internal.setProgressMonitor(createMonitor(job));
-						//change from ABOUT_TO_RUN to RUNNING
-						internal.internalSetState(Job.RUNNING);
-						break;
+						if (internal.isAboutToRunCanceled()) {
+							internal.setAboutToRunCanceled(false);
+							//fall through and end the job below
+						} else {
+							internal.setProgressMonitor(createMonitor(job));
+							//change from ABOUT_TO_RUN to RUNNING
+							internal.internalSetState(Job.RUNNING);
+							break;
+						}
 					}
 				}
 			}