[Lldb-commits] [lldb] [lldb-dap] Refactoring lldb-dap port listening mode to allow multiple connections. (PR #116392)

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Wed Jan 29 01:12:33 PST 2025


================
@@ -5058,72 +5053,148 @@ int main(int argc, char *argv[]) {
   auto terminate_debugger =
       llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); });
 
-  StreamDescriptor input;
-  StreamDescriptor output;
-  std::FILE *redirectOut = nullptr;
-  std::FILE *redirectErr = nullptr;
-  if (portno != -1) {
-    printf("Listening on port %i...\n", portno);
-    SOCKET socket_fd = AcceptConnection(log.get(), portno);
-    if (socket_fd < 0)
-      return EXIT_FAILURE;
+  std::vector<std::string> pre_init_commands;
+  for (const std::string &arg :
+       input_args.getAllArgValues(OPT_pre_init_command)) {
+    pre_init_commands.push_back(arg);
+  }
 
-    input = StreamDescriptor::from_socket(socket_fd, true);
-    output = StreamDescriptor::from_socket(socket_fd, false);
-  } else {
-#if defined(_WIN32)
-    // Windows opens stdout and stdin in text mode which converts \n to 13,10
-    // while the value is just 10 on Darwin/Linux. Setting the file mode to
-    // binary fixes this.
-    int result = _setmode(fileno(stdout), _O_BINARY);
-    assert(result);
-    result = _setmode(fileno(stdin), _O_BINARY);
-    UNUSED_IF_ASSERT_DISABLED(result);
-    assert(result);
-#endif
+  auto HandleClient =
+      [=, log = log.get()](std::string name, StreamDescriptor input,
+                           StreamDescriptor output, std::FILE *redirectOut,
+                           std::FILE *redirectErr) -> bool {
+    DAP dap = DAP(name, program_path.str(), log, default_repl_mode,
+                  std::move(input), std::move(output));
 
-    int stdout_fd = DuplicateFileDescriptor(fileno(stdout));
-    if (stdout_fd == -1) {
+    // stdout/stderr redirection to the IDE's console
+    if (auto Err = dap.ConfigureIO(redirectOut, redirectErr)) {
       llvm::logAllUnhandledErrors(
-          llvm::errorCodeToError(llvm::errnoAsErrorCode()), llvm::errs(),
-          "Failed to configure stdout redirect: ");
+          std::move(Err), llvm::errs(),
+          "Failed to configure lldb-dap IO operations: ");
       return EXIT_FAILURE;
     }
 
-    redirectOut = stdout;
-    redirectErr = stderr;
+    RegisterRequestCallbacks(dap);
 
-    input = StreamDescriptor::from_file(fileno(stdin), false);
-    output = StreamDescriptor::from_file(stdout_fd, false);
-  }
+    dap.pre_init_commands = pre_init_commands;
 
-  DAP dap = DAP(program_path.str(), log.get(), default_repl_mode,
-                std::move(input), std::move(output));
+    // used only by TestVSCode_redirection_to_console.py
+    if (getenv("LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION") != nullptr)
+      redirection_test();
 
-  // stdout/stderr redirection to the IDE's console
-  if (auto Err = dap.ConfigureIO(redirectOut, redirectErr)) {
-    llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
-                                "Failed to configure lldb-dap IO operations: ");
-    return EXIT_FAILURE;
-  }
+    if (auto Err = dap.Loop()) {
+      if (log)
+        *log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n";
+      return false;
+    }
+    return true;
+  };
 
-  RegisterRequestCallbacks(dap);
+  if (!connection.empty()) {
+    auto maybeProtoclAndName = parseConnection(connection);
+    if (auto Err = maybeProtoclAndName.takeError()) {
+      llvm::errs() << "Invalid connection specification " << Err << "\n";
+      return EXIT_FAILURE;
+    }
 
-  for (const std::string &arg :
-       input_args.getAllArgValues(OPT_pre_init_command)) {
-    dap.pre_init_commands.push_back(arg);
-  }
+    Socket::SocketProtocol protocol;
+    std::string name;
+    std::tie(protocol, name) = *maybeProtoclAndName;
 
-  // used only by TestVSCode_redirection_to_console.py
-  if (getenv("LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION") != nullptr)
-    redirection_test();
+    Status error;
+    std::unique_ptr<Socket> listener = Socket::Create(protocol, error);
+    if (error.Fail()) {
+      llvm::errs() << "Failed to create listener for protocol "
+                   << Socket::FindSchemeByProtocol(protocol)
+                   << ", error: " << error.takeError() << "\n";
+      return EXIT_FAILURE;
+    }
 
-  bool CleanExit = true;
-  if (auto Err = dap.Loop()) {
+    error = listener->Listen(name, /* backlog */ 5);
+    if (error.Fail()) {
+      llvm::errs() << "Failed to listen, error: " << error.takeError() << "\n";
+      return EXIT_FAILURE;
+    }
+
+    std::string address =
+        llvm::join(listener->GetListeningConnectionURI(), ", ");
     if (log)
-      *log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n";
-    CleanExit = false;
+      *log << "started with connection listeners " << address << "\n";
+
+    llvm::outs() << "Listening for: " << address << "\n";
+    // Ensure listening address are flushed for calles to retrieve the resolve
+    // address.
+    llvm::outs().flush();
+
+    MainLoop mainloop;
+    mainloop.RegisterSignal(
+        SIGHUP, [](auto &RL) { RL.RequestTermination(); }, error);
+
+    unsigned int clientCount = 0;
+    auto OnAccept = [=, log = log.get(),
+                     &clientCount](std::unique_ptr<Socket> client) {
+      std::string name = llvm::formatv("client_{0}", clientCount++).str();
+
+      if (log) {
+        auto now = std::chrono::duration<double>(
+            std::chrono::system_clock::now().time_since_epoch());
+        *log << llvm::formatv("{0:f9} client connected: {1}", now.count(), name)
+                    .str()
+             << std::endl;
+      }
+      // Start a thread for each connection, unblocking the listening thread.
+      std::thread([=, client = std::move(client)]() {
+        HandleClient(
+            name,
+            StreamDescriptor::from_socket(client->GetNativeSocket(), false),
+            StreamDescriptor::from_socket(client->GetNativeSocket(), false),
+            /*=redirectOut*/ nullptr, /*=redirectErr*/ nullptr);
+      }).detach();
----------------
labath wrote:

What's the shutdown story in this mode? Any chance we could avoid the detached threads?

https://github.com/llvm/llvm-project/pull/116392


More information about the lldb-commits mailing list