Skip to content

Conversation

royitaqi
Copy link
Contributor

@royitaqi royitaqi commented Aug 31, 2025

Patch

Currently, in Server Mode (i.e. --connection), all debuggers are destroyed when the lldb-dap process terminates. This causes logging and release of resources to be delayed. This can also cause congestion if multiple debuggers have the same destroy callbacks, which will fight for the same resources (e.g. web requests) at the same time.

Instead, the debuggers can be destroyed as early as when the debug session terminates. This way, logging and release of release of resources can happen as soon as possible. Congestion can also be naturally reduced, because it's unlikely that all debug sessions will terminate at the same time.

Tests

$ cd build
$ ninja lldb-dap

#################### Run unit tests ####################
$ ninja lldb-unit-test-deps
$ tools/lldb/unittests/DAP/DAPTests
...
[==========] 74 tests from 11 test suites ran. (1414 ms total)
[  PASSED  ] 74 tests.

#################### Run api tests ####################
$ ninja lldb-api-test-deps
$ bin/llvm-lit -a --show-unsupported \
    ../llvm-project/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py \
    ../llvm-project/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py \
    ../llvm-project/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py \
    ../llvm-project/lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py \
    ../llvm-project/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py \
    ../llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py \
    ../llvm-project/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py \
    ../llvm-project/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py \
    ../llvm-project/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
...
UNSUPPORTED: LLDB (/Users/royshi/public_llvm/build/bin/clang-arm64) :: test_basic_functionality (TestDAP_restart_console.TestDAP_restart_console) (skip on debug build type(s))
UNSUPPORTED: LLDB (/Users/royshi/public_llvm/build/bin/clang-arm64) :: test_stopOnEntry (TestDAP_restart_console.TestDAP_restart_console) (skip on debug build type(s))
...
********************
********************
Unsupported Tests (1):
  lldb-api :: tools/lldb-dap/restart/TestDAP_restart_console.py


Testing Time: 71.53s

Total Discovered Tests: 9
  Unsupported: 1 (11.11%)
  Passed     : 8 (88.89%)

@llvmbot
Copy link
Member

llvmbot commented Aug 31, 2025

@llvm/pr-subscribers-lldb

Author: Roy Shi (royitaqi)

Changes

Currently, in Server Mode (i.e. --connection), the destroy callbacks of all debuggers are called at the lldb-dap process's termination. This causes delayed logging and release of resources. This can also cause congestion if all debuggers have the same destroy callbacks, which will fight for the same resources (e.g. web requests) at the same time.

Instead, these can be done earlier, during the disconnect request handling. This way, as soon as the debug session is over, logging and release of release of resources can happen. Congestion is also naturally avoided, because it's unlikely that all debug sessions finish at the same time.


Full diff: https://github.com/llvm/llvm-project/pull/156231.diff

1 Files Affected:

  • (modified) lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp (+5)
diff --git a/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
index 8314a1011a57e..0dfa0b28a20a6 100644
--- a/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
@@ -20,6 +20,11 @@ namespace lldb_dap {
 /// Disconnect request; value of command field is 'disconnect'.
 Error DisconnectRequestHandler::Run(
     const std::optional<DisconnectArguments> &arguments) const {
+  // Destroy the debugger at disconnection. This will trigger the debugger's
+  // destroy callbacks for earlier logging and clean-ups, rather than waiting
+  // until the lldb-dap process's termination.
+  lldb::SBDebugger::Destroy(dap.debugger);
+
   bool terminateDebuggee = !dap.is_attach;
 
   if (arguments && arguments->terminateDebuggee)

@royitaqi royitaqi force-pushed the destroy-debugger-at-disconnect branch from 60a32e3 to c35a97f Compare August 31, 2025 10:45
@royitaqi royitaqi changed the title [lldb-dap] Destroy debugger at disconnect request [lldb-dap] Destroy debugger when debug session terminates Aug 31, 2025
@kusmour
Copy link
Contributor

kusmour commented Aug 31, 2025

I think this is fine. BTW, do we reset the global settings with lldb-dap server mode?

@walter-erquinigo
Copy link
Member

do you know if destroying the debugger will free the module cache?

@royitaqi
Copy link
Contributor Author

royitaqi commented Sep 1, 2025

do you know if destroying the debugger will free the module cache?

@walter-erquinigo: I assume, by "module cache", you meant the global module list accessible by ModuleList::GetSharedModule() and ModuleList::GetSharedModuleList().

I believe destroying the debugger will NOT free it (which I think is the desired behavior). Verified by the commands below, where the Module object of the main executable wasn't deleted nor did its memory address change (as printed by the -p flag) after the first session has terminated.

// Server mode.
// 1st session, after target creation.
(lldb) image list -u -p -f -S -g
[  0] 091DE3B7-FE99-4174-BE03-4F90EFEB4584 0x12b780128 /Users/royshi/demo/simple/a.out 
      /Users/royshi/demo/simple/a.out.dSYM/Contents/Resources/DWARF/a.out
...

// 2nd session, before target creation (as init command).
(lldb) image list -u -p -f -S -g
[  0] 091DE3B7-FE99-4174-BE03-4F90EFEB4584 0x12b780128 /Users/royshi/demo/simple/a.out 
      /Users/royshi/demo/simple/a.out.dSYM/Contents/Resources/DWARF/a.out
...

@walter-erquinigo
Copy link
Member

Good, this looks good to me!
I'll let @kusmour do the final approval

Copy link
Contributor

@kusmour kusmour left a comment

Choose a reason for hiding this comment

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

lgtm just need to clear the test error

Copy link

github-actions bot commented Sep 2, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@royitaqi
Copy link
Contributor Author

royitaqi commented Sep 3, 2025

FYI @kusmour, @walter-erquinigo, @JDevlieghere, that I have made changes to the patch after you guys approved (btw, thanks for the review).

Changes:

  • I had to move the SBDebugger::Destroy() call to be at the end of the DAP::Loop(), specifically after the DAP::StopEventHandlers() call. Below are details.

I will leave this patch open for another 1-2 days before merging, in case you guys have objections about the new code.

--- Details: ---

Two things happened after you guys approved the original patch (c35a97f):

  1. That commit caused a race condition and potential deadlock between the request handler thread and the event thread, where we are being asked to disconnect while the debugee process exits. This is addressed by b011856 (for more details, see the block of inline comment in b011856).

  2. There is another issue. The Debugger::Destroy() will call its m_listener_sp->Clear(), which removes the event listener from the broadcasters. This will cause DAP::StopEventHandlers() to be unable to stop the event thread, because the listeners are no longer there to hear the eBroadcastBitStopEventThread event. To fix this, I had to move the SBDebugger::Destroy() call to be after the DAP::StopEventHandlers() call. And with this, I can revert the change in b011856, which makes the final patch as small as what you approved - just moved to a new location.

Copy link
Member

@walter-erquinigo walter-erquinigo left a comment

Choose a reason for hiding this comment

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

cool

@royitaqi royitaqi merged commit 10bcf0c into llvm:main Sep 4, 2025
9 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 4, 2025

LLVM Buildbot has detected a new failure on builder cross-project-tests-sie-ubuntu running on doug-worker-1a while building lldb at step 6 "test-build-unified-tree-check-cross-project".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/181/builds/27286

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-cross-project) failure: test (failure)
******************** TEST 'cross-project-tests :: debuginfo-tests/dexter/feature_tests/commands/perfect/expect_watch_value.cpp' FAILED ********************
Exit Code: 2

Command Output (stderr):
--
clang++ -O0 -glldb -std=gnu++11 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_watch_value.cpp -o /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/Output/expect_watch_value.cpp.tmp # RUN: at line 7
+ clang++ -O0 -glldb -std=gnu++11 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_watch_value.cpp -o /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/Output/expect_watch_value.cpp.tmp
"/usr/bin/python3.8" "/home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/llvm-project/cross-project-tests/debuginfo-tests/dexter/dexter.py" test --fail-lt 1.0 -w --debugger lldb-dap --lldb-executable "/home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/build/bin/lldb-dap" --binary /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/Output/expect_watch_value.cpp.tmp -- /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_watch_value.cpp | /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/build/bin/FileCheck /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_watch_value.cpp # RUN: at line 8
+ /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/build/bin/FileCheck /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_watch_value.cpp
+ /usr/bin/python3.8 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/llvm-project/cross-project-tests/debuginfo-tests/dexter/dexter.py test --fail-lt 1.0 -w --debugger lldb-dap --lldb-executable /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/build/bin/lldb-dap --binary /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/Output/expect_watch_value.cpp.tmp -- /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_watch_value.cpp


****************************************


@royitaqi
Copy link
Contributor Author

royitaqi commented Sep 5, 2025

Trying to understand what test that is and what went wrong.

EDIT: Rebuilt and it passed. https://lab.llvm.org/buildbot/#/builders/181/builds/27293

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants