From 20fcce658feb9d80a895b3c52e7de342cece9024 Mon Sep 17 00:00:00 2001 From: Federico Jeanne Date: Tue, 24 Mar 2026 12:43:43 +0100 Subject: [PATCH 1/3] Improve tracing options in JobManager and DeadlockDetector Add the following to the .options file so that one can choose to trace these events via the preferences (General > Tracing): - jobs/yielding - jobs/yielding/detailed - jobs/blockedunblocked Do not log to sysout for the preference "jobs/locks", use the same method as other tracers. Show the name of system jobs that block other jobs in JobManager.reportBlocked(...) --- .../bundles/org.eclipse.core.jobs/.options | 8 ++++++- .../core/internal/jobs/DeadlockDetector.java | 23 +++++++++++-------- .../core/internal/jobs/JobManager.java | 2 +- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/runtime/bundles/org.eclipse.core.jobs/.options b/runtime/bundles/org.eclipse.core.jobs/.options index 46461d286fd..e554fb29ff0 100644 --- a/runtime/bundles/org.eclipse.core.jobs/.options +++ b/runtime/bundles/org.eclipse.core.jobs/.options @@ -1,7 +1,7 @@ # Debugging options for the org.eclipse.core.jobs bundle # NOTE: There is a deadlock risk when using these debug flags in a workspace -# launched from Eclipse due to interaction with a lock in the debugger console. +# launched from Eclipse due to interaction with a lock in the debugger console. # For details: https://bugs.eclipse.org/bugs/show_bug.cgi?id=93968 # Prints debug information on running background jobs @@ -14,4 +14,10 @@ org.eclipse.core.jobs/jobs/locks=false org.eclipse.core.jobs/jobs/errorondeadlock=false # Debug shutdown behaviour org.eclipse.core.jobs/jobs/shutdown=false +# Debug jobs yielding execution so that other (blocked) jobs are given a chance to execute +org.eclipse.core.jobs/jobs/yielding=false +org.eclipse.core.jobs/jobs/yielding/detailed=false +# Debug when jobs are blocked (by other jobs) and unblocked +org.eclipse.core.jobs/jobs/blockedunblocked=false + diff --git a/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/DeadlockDetector.java b/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/DeadlockDetector.java index 7c8513dbe46..d65d992a4bc 100644 --- a/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/DeadlockDetector.java +++ b/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/DeadlockDetector.java @@ -245,10 +245,10 @@ private Thread[] getThreadsOwningLock(ISchedulingRule rule) { } } if ((blocking.isEmpty()) && (JobManager.DEBUG_LOCKS)) { - System.out.println("Lock " + rule + " is involved in deadlock but is not owned by any thread."); //$NON-NLS-1$ //$NON-NLS-2$ + JobManager.debug("Lock " + rule + " is involved in deadlock but is not owned by any thread."); //$NON-NLS-1$ //$NON-NLS-2$ } if ((blocking.size() > 1) && (rule instanceof ILock) && (JobManager.DEBUG_LOCKS)) { - System.out.println("Lock " + rule + " is owned by more than 1 thread, but it is not a rule."); //$NON-NLS-1$ //$NON-NLS-2$ + JobManager.debug("Lock " + rule + " is owned by more than 1 thread, but it is not a rule."); //$NON-NLS-1$ //$NON-NLS-2$ } return blocking.toArray(new Thread[blocking.size()]); } @@ -354,13 +354,13 @@ void lockReleased(Thread owner, ISchedulingRule lock) { //make sure the lock and thread exist in the graph if (threadIndex < 0) { if (JobManager.DEBUG_LOCKS) { - System.out.println("[lockReleased] Lock " + lock + " was already released by thread " + owner.getName()); //$NON-NLS-1$ //$NON-NLS-2$ + JobManager.debug("[lockReleased] Lock " + lock + " was already released by thread " + owner.getName()); //$NON-NLS-1$ //$NON-NLS-2$ } return; } if (lockIndex < 0) { if (JobManager.DEBUG_LOCKS) { - System.out.println("[lockReleased] Thread " + owner.getName() + " already released lock " + lock); //$NON-NLS-1$ //$NON-NLS-2$ + JobManager.debug("[lockReleased] Thread " + owner.getName() + " already released lock " + lock); //$NON-NLS-1$ //$NON-NLS-2$ } return; } @@ -376,7 +376,8 @@ void lockReleased(Thread owner, ISchedulingRule lock) { || lock.isConflicting(locks.get(j)))) { if (graph[threadIndex][j] == NO_STATE) { if (JobManager.DEBUG_LOCKS) { - System.out.println("[lockReleased] More releases than acquires for thread " + owner.getName() + " and lock " + lock); //$NON-NLS-1$ //$NON-NLS-2$ + JobManager.debug("[lockReleased] More releases than acquires for thread " + owner.getName() //$NON-NLS-1$ + + " and lock " + lock); //$NON-NLS-1$ } } else { graph[threadIndex][j]--; @@ -399,13 +400,15 @@ void lockReleasedCompletely(Thread owner, ISchedulingRule rule) { //need to make sure that the given thread and rule were not already removed from the graph if (threadIndex < 0) { if (JobManager.DEBUG_LOCKS) { - System.out.println("[lockReleasedCompletely] Lock " + rule + " was already released by thread " + owner.getName()); //$NON-NLS-1$ //$NON-NLS-2$ + JobManager.debug( + "[lockReleasedCompletely] Lock " + rule + " was already released by thread " + owner.getName()); //$NON-NLS-1$ //$NON-NLS-2$ } return; } if (ruleIndex < 0) { if (JobManager.DEBUG_LOCKS) { - System.out.println("[lockReleasedCompletely] Thread " + owner.getName() + " already released lock " + rule); //$NON-NLS-1$ //$NON-NLS-2$ + JobManager + .debug("[lockReleasedCompletely] Thread " + owner.getName() + " already released lock " + rule); //$NON-NLS-1$ //$NON-NLS-2$ } return; } @@ -464,20 +467,20 @@ void lockWaitStop(Thread owner, ISchedulingRule lock) { //make sure the thread and lock exist in the graph if (threadIndex < 0) { if (JobManager.DEBUG_LOCKS) { - System.out.println("Thread " + owner.getName() + " was already removed."); //$NON-NLS-1$ //$NON-NLS-2$ + JobManager.debug("Thread " + owner.getName() + " was already removed."); //$NON-NLS-1$ //$NON-NLS-2$ } return; } if (lockIndex < 0) { if (JobManager.DEBUG_LOCKS) { - System.out.println("Lock " + lock + " was already removed."); //$NON-NLS-1$ //$NON-NLS-2$ + JobManager.debug("Lock " + lock + " was already removed."); //$NON-NLS-1$ //$NON-NLS-2$ } return; } if (graph[threadIndex][lockIndex] != WAITING_FOR_LOCK) { // Lock has already been granted, nothing to do... if (JobManager.DEBUG_LOCKS) { - System.out.println("Lock " + lock + " already granted to depth: " + graph[threadIndex][lockIndex]); //$NON-NLS-1$ //$NON-NLS-2$ + JobManager.debug("Lock " + lock + " already granted to depth: " + graph[threadIndex][lockIndex]); //$NON-NLS-1$ //$NON-NLS-2$ } return; } diff --git a/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java b/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java index ef4005f7069..5011c06d3c3 100644 --- a/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java +++ b/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java @@ -1395,7 +1395,7 @@ final void reportBlocked(IProgressMonitor monitor, Collection block IStatus reason; InternalJob blockingJob = blockingJobs.stream().sorted(Comparator.comparing(InternalJob::isSystem)).findFirst() .orElse(null); - if (blockingJob == null || blockingJob instanceof ThreadJob || blockingJob.isSystem()) { + if (blockingJob == null || blockingJob instanceof ThreadJob) { reason = new Status(IStatus.INFO, JobManager.PI_JOBS, 1, JobMessages.jobs_blocked0, null); } else { String msg = NLS.bind(JobMessages.jobs_blocked1, blockingJob.getName()); From df90062e11f5eb54bcdd531bf1be32cbe3416711 Mon Sep 17 00:00:00 2001 From: Federico Jeanne Date: Tue, 24 Mar 2026 13:05:30 +0100 Subject: [PATCH 2/3] Version bump(s) for 4.40 stream --- runtime/bundles/org.eclipse.core.jobs/META-INF/MANIFEST.MF | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1991fbccb97..be708b1eead 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.700.qualifier +Bundle-Version: 3.15.800.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: org.eclipse.core.internal.jobs;x-internal:=true, From d47e41e6f643e274cdf1440321574381636a47b3 Mon Sep 17 00:00:00 2001 From: Federico Jeanne Date: Wed, 25 Mar 2026 11:04:21 +0100 Subject: [PATCH 3/3] Preserve the current values when loading debug options in JobManager Do not set them to false if they are not explicitly set in the configuration, leave them as they are. This avoids the duplicated logic of declaring them as "false" when they are declared and also when they are loaded. --- .../eclipse/core/internal/jobs/JobManager.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java b/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java index 5011c06d3c3..35c65144e03 100644 --- a/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java +++ b/runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobManager.java @@ -1366,14 +1366,14 @@ private long lifeTimeInMs() { @Override public void optionsChanged(DebugOptions options) { DEBUG_TRACE = options.newDebugTrace(PI_JOBS); - DEBUG = options.getBooleanOption(OPTION_DEBUG_JOBS, false); - DEBUG_BEGIN_END = options.getBooleanOption(OPTION_DEBUG_BEGIN_END, false); - DEBUG_YIELDING = options.getBooleanOption(OPTION_DEBUG_YIELDING, false); - DEBUG_YIELDING_DETAILED = options.getBooleanOption(OPTION_DEBUG_YIELDING_DETAILED, false); - DEBUG_DEADLOCK = options.getBooleanOption(OPTION_DEADLOCK_ERROR, false); - DEBUG_LOCKS = options.getBooleanOption(OPTION_LOCKS, false); - DEBUG_SHUTDOWN = options.getBooleanOption(OPTION_SHUTDOWN, false); - DEBUG_BLOCKED_UNBLOCKED = options.getBooleanOption(OPTION_DEBUG_BLOCKED_UNBLOCKED, false); + DEBUG = options.getBooleanOption(OPTION_DEBUG_JOBS, DEBUG); + DEBUG_BEGIN_END = options.getBooleanOption(OPTION_DEBUG_BEGIN_END, DEBUG_BEGIN_END); + DEBUG_YIELDING = options.getBooleanOption(OPTION_DEBUG_YIELDING, DEBUG_YIELDING); + DEBUG_YIELDING_DETAILED = options.getBooleanOption(OPTION_DEBUG_YIELDING_DETAILED, DEBUG_YIELDING_DETAILED); + DEBUG_DEADLOCK = options.getBooleanOption(OPTION_DEADLOCK_ERROR, DEBUG_DEADLOCK); + DEBUG_LOCKS = options.getBooleanOption(OPTION_LOCKS, DEBUG_LOCKS); + DEBUG_SHUTDOWN = options.getBooleanOption(OPTION_SHUTDOWN, DEBUG_SHUTDOWN); + DEBUG_BLOCKED_UNBLOCKED = options.getBooleanOption(OPTION_DEBUG_BLOCKED_UNBLOCKED, DEBUG_BLOCKED_UNBLOCKED); } @Override