diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/builders/ParallelBuildChainTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/builders/ParallelBuildChainTest.java index 3309eca97b6..5e1b78c1ec4 100644 --- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/builders/ParallelBuildChainTest.java +++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/builders/ParallelBuildChainTest.java @@ -141,6 +141,17 @@ public void testIndividualProjectBuilds_ProjectRelaxedRule() throws Exception { }); } + @Test + public void testIndividualProjectBuilds_WithManyProjects_ProjectRelaxedRule() throws Exception { + int numberOfParallelBuilds = 60; + var longRunningProjects = createMultipleTestProjects(numberOfParallelBuilds, BuildDurationType.LONG_RUNNING, + RuleType.CURRENT_PROJECT_RELAXED); + executeIndividualFullProjectBuilds(numberOfParallelBuilds, () -> { + assertBuildsToStart(getAllProjects()); + assertMinimumNumberOfSimultaneousBuilds(longRunningProjects.size()); + }); + } + @Test public void testWorkspaceBuild_NoConflictRule() throws Exception { int numberOfParallelBuilds = 3; diff --git a/runtime/bundles/org.eclipse.core.jobs/META-INF/MANIFEST.MF b/runtime/bundles/org.eclipse.core.jobs/META-INF/MANIFEST.MF index 5b598798272..18a7aebcca2 100644 --- a/runtime/bundles/org.eclipse.core.jobs/META-INF/MANIFEST.MF +++ b/runtime/bundles/org.eclipse.core.jobs/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.core.jobs; singleton:=true -Bundle-Version: 3.15.0.qualifier +Bundle-Version: 3.15.100.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: org.eclipse.core.internal.jobs;x-internal:=true, diff --git a/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/ThreadJob.java b/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/ThreadJob.java index 6ed718fdcd1..15c8828b3a1 100644 --- a/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/ThreadJob.java +++ b/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/ThreadJob.java @@ -15,8 +15,14 @@ import java.util.List; import org.eclipse.core.internal.runtime.RuntimeLog; -import org.eclipse.core.runtime.*; -import org.eclipse.core.runtime.jobs.*; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.jobs.LockListener; /** * Captures the implicit job state for a given thread. @@ -317,11 +323,16 @@ private static ThreadJob waitForRun(final ThreadJob threadJob, IProgressMonitor // The actual exit conditions are listed above at the beginning of // this while loop int state = blockingJob.getState(); - //ensure we don't wait forever if the blocker is waiting, because it might have yielded to me - if (state == Job.RUNNING && canBlock) { - blockingJob.jobStateLock.wait(); - } else if (state != Job.NONE) { - blockingJob.jobStateLock.wait(250); + // Check that blockingJob has not acquired a different, non-conflicting + // scheduling rule since checking for conflicts by JobManager + if (state != Job.NONE && blockingJob.getRule().isConflicting(threadJob.getRule())) { + // ensure we don't wait forever if the blocker is waiting, because it might have + // yielded to me + if (state == Job.RUNNING && canBlock) { + blockingJob.jobStateLock.wait(); + } else { + blockingJob.jobStateLock.wait(250); + } } } catch (InterruptedException e) { // This thread may be interrupted via two common scenarios. 1) If