[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)
----------------
labath wrote:
Any reason for choosing this format? I think [formatv("{0}", now()](https://github.com/llvm/llvm-project/blob/51c7338cc671c90ba9345b53c7ca01dc461341ed/llvm/unittests/Support/Chrono.cpp#L57) should just work and produce something more readable (to humans at least)
https://github.com/llvm/llvm-project/pull/116392
More information about the lldb-commits
mailing list