Skip to content

IEP-1771 Deadlock when terminating a stuck OpenOCD/GDB launch sequence#1484

Open
sigmaaa wants to merge 4 commits into
masterfrom
fix_debug_hangs
Open

IEP-1771 Deadlock when terminating a stuck OpenOCD/GDB launch sequence#1484
sigmaaa wants to merge 4 commits into
masterfrom
fix_debug_hangs

Conversation

@sigmaaa

@sigmaaa sigmaaa commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Description

Fixes ESP-IDF OpenOCD/GDB debug sessions that hang indefinitely during launch or when pressing Stop — especially when the target is unresponsive or stuck in a reset loop.

  • Adds bounded timeouts for OpenOCD startup (30s), GDB initialization (60s), and GDB spawn (30s)
  • Introduces reliable process cleanup via LaunchProcessDictionary: force-kills OpenOCD/GDB, closes MI pipes, stops GDB CLI console jobs
  • On Stop: lets CDT run graceful shutdown first, then force-kills OS processes so the session can complete
  • Adds a 3s safety-net re-cleanup if the DSF session is still active
  • Makes process termination cross-platform (process tree kill; taskkill on Windows, kill -9 on POSIX)
  • Refactors OpenOCD-only launch for app-level tracing and fixes duplicate Debugger tab in launch config UI

Fixes # (IEP-1771)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)

How has this been tested?

  • Start debug on a connected board → set breakpoint → Stop. Session ends cleanly; no leftover openocd or gdb in Task Manager / Activity Monitor.
  • Stuck target: Start debug with board in a bad state (or trigger reset loop) → press Stop. Session ends within a few seconds; Stop button releases; adapter is free for relaunch.
  • Unplug during launch: Unplug the board while launch is in progress (or cancel from the progress dialog). Launch aborts within ~30–60s with an error; no orphan processes.
  • Bad OpenOCD config: Use a busy GDB port or invalid config → launch fails with timeout/error; cleanup runs; next launch works.
  • Rapid relaunch: After a failed or stuck session, start debug again immediately. Launch succeeds.
  • App-level tracing: Start app-level tracing (OpenOCD only, no GDB client) → Stop. OpenOCD is cleaned up.
  • Windows, Mac: Repeat stuck-Stop scenario on Windows and confirm no orphan openocd.exe processes.

UI: Open Debug Configurations → confirm only one Debugger tab is shown.

Test Configuration:

  • ESP-IDF Version:
  • OS (Windows,Linux and macOS):

Dependent components impacted by this PR:

  • Debug session
  • Tab debugger

Checklist

  • PR Self Reviewed
  • Applied Code formatting
  • Added Documentation
  • Added Unit Test
  • Verified on all platforms - Windows,Linux and macOS

Summary by CodeRabbit

  • New Features
    • Added the ability to launch OpenOCD independently without starting the GDB client.
  • Bug Fixes
    • Improved cleanup on debug termination by reliably stopping related consoles and canceling stuck GDB CLI background jobs.
    • Increased robustness of GDB/OpenOCD startup and failure handling with bounded timeouts and clearer error reporting.
    • Strengthened process shutdown to prevent hung or lingering debug sessions.
  • Refactor
    • Updated server port handling to read pre-assigned ports from launch settings and introduced a dedicated port allocation step.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4255d993-a888-4c97-9dd7-4ce76cc60cc3

📥 Commits

Reviewing files that changed from the base of the PR and between 6bc76a5 and e3046f6.

📒 Files selected for processing (1)
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java

📝 Walkthrough

Walkthrough

This PR overhauls the OpenOCD/GDB debug launch lifecycle in the IDF Eclipse plugin: port allocation is moved out of command-line construction into a dedicated pre-launch phase; LaunchProcessDictionary is redesigned to track processes by ILaunch with force-kill escalation and cross-platform process-tree termination; bounded timeouts are applied throughout startup and initialization; an OpenOCD-only launch mode is introduced via LaunchOptions; and process teardown is strengthened in GdbBackend, IdfRuntimeProcess, and Launch.

Changes

OpenOCD/GDB Launch Lifecycle Overhaul

Layer / File(s) Summary
Port allocation separated from command-line construction
bundles/.../Configuration.java, bundles/.../Activator.java, bundles/.../plugin.xml
getGdbServerCommandLineArray reads pre-assigned GDB/Telnet/TCL ports from ILaunchConfiguration; new allocateServerPorts performs one-time allocation on an in-memory working copy before server startup; Activator adds the OPENOCD_STARTUP_TIMEOUT_STATUS constant; plugin.xml whitespace adjusted.
LaunchOptions value object and OpenOCD-only mode wiring
bundles/.../dsf/LaunchOptions.java, bundles/.../dsf/LaunchConfigurationDelegate.java, bundles/.../ui/AppLvlTracingHandler.java
LaunchOptions is a new immutable value class; LaunchConfigurationDelegate stores it in a ThreadLocal, uses it to disable GDB client start, and exposes runOpenOcdOnlyLaunch; GDB version parsing simplified; AppLvlTracingHandler delegates to that entry point.
LaunchProcessDictionary redesign with concurrent ILaunch-keyed maps
bundles/.../dsf/LaunchProcessDictionary.java
Rewritten with ConcurrentHashMaps keyed by ILaunch for IProcess wrappers and OS PIDs; adds registerBackendProcess, forceKillOsProcesses, terminateProcessMonitors, and forceTerminateLaunch; escalates termination from destroydestroyForcibly → OS-native taskkill/kill -9; includes executor-based DSF backend discovery and process-tree destruction primitives.
Console cleanup and IdfRuntimeProcess teardown
bundles/.../dsf/GdbConsoleCleanup.java, bundles/.../dsf/process/IdfRuntimeProcess.java
GdbConsoleCleanup stops CDT debugger consoles and cancels stuck GDB CLI jobs. IdfRuntimeProcess adds forceTerminateWithoutWait: guards on isTerminated, calls killStreamMonitors, then forcibly destroys the system process with AbstractCLIProcess-specific handling and destroyForcibly escalation.
Launch class refactor with DSF simplification
bundles/.../dsf/Launch.java
Removes cached DSF session/executor fields; adds fDoStartGdbServer/fDoStartGdbClient flags, clearProcessReferences, and scheduleSafetyNetCleanup job; terminate tolerates RejectedExecutionException and force-kills OS processes; console/process registration uses ILaunch-keyed dictionary APIs; addServerProcess uses on-demand DsfServicesTracker.
GdbBackend startup and teardown hardening
bundles/.../dsf/GdbBackend.java
Replaces bespoke monitor state with an AtomicBoolean startup gate using compareAndSet; spawns a daemon thread to drain MI error output for bounded time; registers GDB process in LaunchProcessDictionary; escalates destroy to destroyForcibly after 2 seconds; refactors MonitorJob with an explicit lock object, volatile fMonitorExited flag, executor-based dispatch of termination, and an isMonitorExited() accessor.
GdbServerBackend OpenOCD process registration
bundles/.../dsf/GdbServerBackend.java
launchGdbServerProcess captures the spawned Process and registers it in LaunchProcessDictionary under the key "openocd" when the launch model adapter is available.
LaunchConfigurationDelegate bounded timeouts and async cleanup
bundles/.../dsf/LaunchConfigurationDelegate.java
Adds a daemon cancel-watcher thread that terminates the ILaunch and interrupts the main thread on cancellation; restructures launchDebugSession with GDB-client-conditional service-factory setup; OpenOCD readiness polling uses a bounded deadline computed from SERVER_STATUS_POLL_TIMEOUT_MS, throwing OPENOCD_STARTUP_TIMEOUT_STATUS on expiry; final initialization order adjusted, completeInitialization bounded by COMPLETE_INIT_TIMEOUT_MS, and cleanupLaunch replaced with an async job that tolerates RejectedExecutionException.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(70, 130, 180, 0.5)
    note over AppLvlTracingHandler,Launch: OpenOCD-only launch path
  end
  AppLvlTracingHandler->>LaunchConfigurationDelegate: runOpenOcdOnlyLaunch(config, mode, monitor)
  LaunchConfigurationDelegate->>LaunchConfigurationDelegate: pendingLaunchOptions.set(LaunchOptions.openOcdOnly())
  LaunchConfigurationDelegate->>Launch: createGdbLaunch → setDoStartGdbClient(false)

  rect rgba(60, 179, 113, 0.5)
    note over LaunchConfigurationDelegate,GdbServerBackend: OpenOCD server startup with bounded poll
  end
  LaunchConfigurationDelegate->>Configuration: allocateServerPorts(workingCopy)
  LaunchConfigurationDelegate->>GdbServerBackend: getServerServicesSequence()
  GdbServerBackend->>LaunchProcessDictionary: registerBackendProcess("openocd", process)
  loop poll ≤ SERVER_STATUS_POLL_TIMEOUT_MS
    LaunchConfigurationDelegate->>GdbServerBackend: getServerState()
  end
  alt timeout
    LaunchConfigurationDelegate->>LaunchProcessDictionary: killAllProcessesInLaunch(launch)
    LaunchConfigurationDelegate-->>AppLvlTracingHandler: throw CoreException(OPENOCD_STARTUP_TIMEOUT_STATUS)
  end

  rect rgba(255, 165, 0, 0.5)
    note over LaunchConfigurationDelegate,GdbBackend: Full debug launch — GDB startup
  end
  LaunchConfigurationDelegate->>GdbBackend: getServicesSequence()
  GdbBackend->>GdbBackend: daemon thread drains MI error stream
  GdbBackend->>LaunchProcessDictionary: registerBackendProcess("gdb", process)
  LaunchConfigurationDelegate->>LaunchConfigurationDelegate: completeLaunchQuery.get(COMPLETE_INIT_TIMEOUT_MS)
  alt timeout
    LaunchConfigurationDelegate->>Launch: cleanupLaunch (async Job)
    LaunchConfigurationDelegate-->>LaunchConfigurationDelegate: throw DebugException "Debugger initialization timed out"
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • espressif/idf-eclipse-plugin#1023: Both PRs modify Configuration.java's port-allocation flow for OpenOCD/GDB server ports, moving or refactoring ATTR_PORT_NUMBER and related logic used to build the GDB server command line.
  • espressif/idf-eclipse-plugin#1226: Both PRs modify GdbServerBackend.launchGdbServerProcess(...), with this PR adding process registration via LaunchProcessDictionary and the other PR extending the method for environment/working directory setup.

Suggested labels

macos

Suggested reviewers

  • AndriiFilippov
  • kolipakakondal

Poem

🐇 Hoppity-hop through the debug land,
Ports get allocated, well in advance!
Force-kill cascades from destroy to SIGKILL,
Timeouts now bounded — no infinite wait!
The safety-net job keeps the session in check,
OpenOCD-only? One flag does the trick.
This bunny approves — clean launches at last! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.31% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'IEP-1771 Deadlock when terminating a stuck OpenOCD/GDB launch sequence' directly and specifically describes the main issue being addressed: fixing deadlocks during termination of stuck OpenOCD/GDB sessions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix_debug_hangs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java (2)

167-179: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make the GDB-version timeout actually terminate stubborn processes.

The timeout job only calls process.destroy(). If the spawned command ignores graceful termination, the stdout reader can remain blocked and the 10-second timeout does not bound getGDBVersion().

Proposed fix
 `@Override`
 protected IStatus run(IProgressMonitor arg)
 {
 	process.destroy();
+	try
+	{
+		if (!process.waitFor(2, TimeUnit.SECONDS))
+		{
+			process.destroyForcibly();
+		}
+	}
+	catch (InterruptedException e)
+	{
+		Thread.currentThread().interrupt();
+		process.destroyForcibly();
+	}
 	return Status.OK_STATUS;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java`
around lines 167 - 179, The timeout job in the anonymous Job class only calls
process.destroy() which performs graceful termination that can be ignored by
stubborn processes, leaving the stdout reader blocked. In the run method of the
timeout job, after calling process.destroy(), also call
process.destroyForcibly() to forcefully terminate the process if it does not
respond to the graceful termination within a short window, ensuring the
10-second timeout actually bounds the getGDBVersion() operation.

429-470: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep server-status polling bounded and fail closed on executor errors.

The deadline check is bypassed while Line 445 waits on an unbounded get(). If the DSF executor is stuck, this can still hang indefinitely; if the status query throws, Lines 467-470 only log and continue launching without a verified OpenOCD server.

Proposed fix
+import java.util.concurrent.Future;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-					Thread.sleep(SERVER_STATUS_POLL_INTERVAL_MS);
-					serverStatus = launch.getSession().getExecutor().submit(callable).get();
+					long waitMs = Math.min(SERVER_STATUS_POLL_INTERVAL_MS,
+							Math.max(1, deadline - System.currentTimeMillis()));
+					Future<IStatus> serverStatusFuture = launch.getSession().getExecutor().submit(callable);
+					try
+					{
+						serverStatus = serverStatusFuture.get(waitMs, TimeUnit.MILLISECONDS);
+					}
+					catch (TimeoutException e)
+					{
+						serverStatusFuture.cancel(false);
+					}
 				}
 
 				if (serverStatus != Status.OK_STATUS)
@@
 			catch (InterruptedException e)
 			{
 				if (monitor.isCanceled())
 				{
 					cleanupLaunch(launch);
 					return;
 				}
-				Activator.log(e);
+				Thread.currentThread().interrupt();
+				cleanupLaunch(launch);
+				throw new DebugException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+						DebugException.INTERNAL_ERROR, "Interrupted", e));
 			}
 			catch (ExecutionException e)
 			{
-				Activator.log(e);
+				cleanupLaunch(launch);
+				throw new DebugException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+						DebugException.REQUEST_FAILED, "Error reading OpenOCD server status", e.getCause()));
 			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java`
around lines 429 - 470, The polling loop has two issues: the unbounded get()
call on the executor submit bypasses the deadline check and can hang
indefinitely, and ExecutionException errors only log without failing the launch.
Fix this by using a time-bounded get(timeout, unit) call that respects the
remaining deadline calculated from the deadline variable, and change the
ExecutionException catch block to call cleanupLaunch and throw a CoreException
instead of just logging with Activator.log(e).
🧹 Nitpick comments (3)
bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbConsoleCleanup.java (1)

82-96: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Job cancellation relies on fragile string matching.

The cancelGdbCliReadJobs() method identifies jobs by checking if their name contains "GDB CLI". If CDT changes job naming conventions in a future version, this could silently fail to cancel the intended jobs. Consider documenting this coupling or adding a fallback mechanism.

That said, this is acceptable for a cleanup utility where missing a job just means slightly delayed cleanup rather than data corruption.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbConsoleCleanup.java`
around lines 82 - 96, The cancelGdbCliReadJobs() method relies on fragile string
matching to identify jobs by checking if the job name contains the
GDB_CLI_JOB_MARKER constant. This creates an undocumented coupling with CDT's
job naming conventions that could silently fail if CDT changes their naming. Add
a comment above the method or near the string matching logic in
cancelGdbCliReadJobs() that documents this dependency on the specific
GDB_CLI_JOB_MARKER naming convention used by CDT, or alternatively implement a
fallback mechanism to handle cases where the naming convention might change.
bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java (1)

386-408: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

POSIX kill -9 does not terminate child processes like Windows taskkill /T.

On Windows, taskkill /F /T /PID terminates the entire process tree. On POSIX, kill -9 <pid> only terminates the specified process, leaving children orphaned. Since the JVM's ProcessHandle.descendants() snapshot and destroyTree() should have already handled children, this fallback may be less effective on POSIX if any descendants were missed.

Consider using pkill -9 -P <pid> or iterating through /proc/<pid>/task/*/children for true tree termination on Linux, though this may be acceptable if the earlier destroyTree() calls typically succeed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java`
around lines 386 - 408, In the killTreeViaOsCommand method, the POSIX branch
uses kill -9 which only terminates the specified process without affecting
children, unlike the Windows taskkill /T which kills the entire process tree.
Replace the kill -9 command in the else block with pkill -9 -P to kill both the
parent process and its direct children, making the behavior consistent with the
Windows approach. This will ensure child processes are properly terminated on
POSIX systems in the fallback scenario.
bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java (1)

1008-1010: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Unusual usage of Thread.interrupted() - consider clarifying intent.

Thread.interrupted() reads and clears the interrupt status, but the return value is discarded. Since the job is ending anyway and swallowing the interrupt is intentional, either remove the call entirely (empty catch is fine), or replace with a comment explaining the intent.

Suggested alternatives

Option A - Empty catch with comment:

 catch (InterruptedException ie)
 {
-    Thread.interrupted();
+    // Intentionally swallowed: job is ending regardless
 }

Option B - Just clear the flag explicitly:

 catch (InterruptedException ie)
 {
-    Thread.interrupted();
+    Thread.interrupted(); // Clear the flag; job is exiting anyway
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java`
around lines 1008 - 1010, The catch block for InterruptedException in the
GdbBackend class is calling Thread.interrupted() but discarding the return
value, making the intent unclear. Either add a comment above the
Thread.interrupted() call explaining that the interrupt flag is being
intentionally cleared before the job ends, or remove the call entirely and add a
comment explaining why the interrupt is being swallowed. Choose the approach
that best reflects your intent for handling this interrupt.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Configuration.java`:
- Around line 345-348: The allocateServerPorts method always starts from the
default GDB port when allocating a port, which ignores any user-configured port
preference already stored in the configuration under
IGDBJtagConstants.ATTR_PORT_NUMBER. Before calling
PortChecker.getAvailablePort(), first check if the configuration already has a
port number attribute set; if it does, pass that configured port as the
preferred starting point to getAvailablePort instead of always using
DefaultPreferences.GDB_SERVER_GDB_PORT_NUMBER_DEFAULT. Only use the default port
as a fallback if no prior configuration exists.

In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java`:
- Around line 129-137: The issue is that when OpenOCD-only mode is active
(checked via options.isOpenOcdOnly()), the code only sets the launch instance's
doStartGdbClient flag to false, but does not update the working copy
configuration. Since GdbServerBackend.initialize reads the DO_START_GDB_CLIENT
attribute directly from the launch configuration using
Configuration.getDoStartGdbClient(fLaunchConfiguration), the change to the
launch instance alone is insufficient. In the if block where
options.isOpenOcdOnly() is true, after calling
launch.setDoStartGdbClient(false), also set the DO_START_GDB_CLIENT attribute in
the working copy (wc) to false so that GdbServerBackend.initialize will read the
correct value when it later queries the launch configuration.

---

Outside diff comments:
In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java`:
- Around line 167-179: The timeout job in the anonymous Job class only calls
process.destroy() which performs graceful termination that can be ignored by
stubborn processes, leaving the stdout reader blocked. In the run method of the
timeout job, after calling process.destroy(), also call
process.destroyForcibly() to forcefully terminate the process if it does not
respond to the graceful termination within a short window, ensuring the
10-second timeout actually bounds the getGDBVersion() operation.
- Around line 429-470: The polling loop has two issues: the unbounded get() call
on the executor submit bypasses the deadline check and can hang indefinitely,
and ExecutionException errors only log without failing the launch. Fix this by
using a time-bounded get(timeout, unit) call that respects the remaining
deadline calculated from the deadline variable, and change the
ExecutionException catch block to call cleanupLaunch and throw a CoreException
instead of just logging with Activator.log(e).

---

Nitpick comments:
In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java`:
- Around line 1008-1010: The catch block for InterruptedException in the
GdbBackend class is calling Thread.interrupted() but discarding the return
value, making the intent unclear. Either add a comment above the
Thread.interrupted() call explaining that the interrupt flag is being
intentionally cleared before the job ends, or remove the call entirely and add a
comment explaining why the interrupt is being swallowed. Choose the approach
that best reflects your intent for handling this interrupt.

In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbConsoleCleanup.java`:
- Around line 82-96: The cancelGdbCliReadJobs() method relies on fragile string
matching to identify jobs by checking if the job name contains the
GDB_CLI_JOB_MARKER constant. This creates an undocumented coupling with CDT's
job naming conventions that could silently fail if CDT changes their naming. Add
a comment above the method or near the string matching logic in
cancelGdbCliReadJobs() that documents this dependency on the specific
GDB_CLI_JOB_MARKER naming convention used by CDT, or alternatively implement a
fallback mechanism to handle cases where the naming convention might change.

In
`@bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java`:
- Around line 386-408: In the killTreeViaOsCommand method, the POSIX branch uses
kill -9 which only terminates the specified process without affecting children,
unlike the Windows taskkill /T which kills the entire process tree. Replace the
kill -9 command in the else block with pkill -9 -P to kill both the parent
process and its direct children, making the behavior consistent with the Windows
approach. This will ensure child processes are properly terminated on POSIX
systems in the fallback scenario.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6bd089f5-4155-4bd1-a999-0136ac8d480c

📥 Commits

Reviewing files that changed from the base of the PR and between 182afe5 and 97e217e.

📒 Files selected for processing (12)
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Activator.java
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Configuration.java
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbConsoleCleanup.java
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbServerBackend.java
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchOptions.java
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/process/IdfRuntimeProcess.java
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/ui/AppLvlTracingHandler.java
💤 Files with no reviewable changes (1)
  • bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml

@kolipakakondal kolipakakondal added this to the v4.4.0 milestone Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants