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; + } } } }