================ @@ -421,97 +417,210 @@ int main_platform(int argc, char *argv[]) { return 0; } - const bool children_inherit_listen_socket = false; + if (gdbserver_port != 0 && + (gdbserver_port < LOW_PORT || gdbserver_port > HIGH_PORT)) { + WithColor::error() << llvm::formatv("Port number {0} is not in the " + "valid user port range of {1} - {2}\n", + gdbserver_port, LOW_PORT, HIGH_PORT); + return 1; + } + // the test suite makes many connections in parallel, let's not miss any. // The highest this should get reasonably is a function of the number // of target CPUs. For now, let's just use 100. const int backlog = 100; - std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create( - listen_host_port, children_inherit_listen_socket, error)); - if (error.Fail()) { - fprintf(stderr, "failed to create acceptor: %s", error.AsCString()); - exit(socket_error); + std::unique_ptr<Socket> sock_named; + std::unique_ptr<TCPSocket> sock_platform; + std::unique_ptr<TCPSocket> sock_gdb; + std::string hostname; + uint16_t platform_port = 0; + Socket::SocketProtocol protocol = Socket::ProtocolUnixDomain; + + // Try to match socket name as URL - e.g., tcp://localhost:5555 + if (std::optional<URI> uri = URI::Parse(listen_host_port)) { + if (!Socket::FindProtocolByScheme(uri->scheme.str().c_str(), protocol)) { + fprintf(stderr, "Unknown protocol scheme \"%s\".", + uri->scheme.str().c_str()); + return socket_error; + } + if (protocol == Socket::ProtocolTcp) { + hostname = uri->hostname; + if (uri->port) { + platform_port = *(uri->port); + } + } else + hostname = listen_host_port.substr(uri->scheme.size() + strlen("://")); + } else { + // Try to match socket name as $host:port - e.g., localhost:5555 + llvm::Expected<Socket::HostAndPort> host_port = + Socket::DecodeHostAndPort(listen_host_port); + if (!llvm::errorToBool(host_port.takeError())) { + protocol = Socket::ProtocolTcp; + hostname = host_port->hostname; + platform_port = host_port->port; + } else + hostname = listen_host_port; } - error = acceptor_up->Listen(backlog); - if (error.Fail()) { - printf("failed to listen: %s\n", error.AsCString()); - exit(socket_error); + std::string socket_id; + if (protocol == Socket::ProtocolTcp) { + if (platform_port != 0 && platform_port == gdbserver_port) { + fprintf(stderr, "The same platform and gdb ports %u.", platform_port); + return socket_error; + } + + sock_platform = std::make_unique<TCPSocket>( + /*should_close=*/true, /*child_processes_inherit=*/false); + error = sock_platform->Listen( + llvm::formatv("{0}:{1}", hostname, platform_port).str(), backlog); + if (error.Fail()) { + printf("Failed to listen platform: %s\n", error.AsCString()); + return socket_error; + } + if (platform_port == 0) + platform_port = sock_platform->GetLocalPortNumber(); + if (platform_port != 0) + socket_id = llvm::to_string(platform_port); + + sock_gdb = std::make_unique<TCPSocket>(/*should_close=*/true, + /*child_processes_inherit=*/false); + error = sock_gdb->Listen( + llvm::formatv("{0}:{1}", hostname, gdbserver_port).str(), backlog); + if (error.Fail()) { + printf("Failed to listen gdb: %s\n", error.AsCString()); + return socket_error; + } + if (gdbserver_port == 0) + gdbserver_port = sock_gdb->GetLocalPortNumber(); + } else { + if (g_server) { + fprintf(stderr, + "Ambiguous parameters --server --listen %s\n" + "The protocol must be tcp for the server mode.", + listen_host_port.c_str()); + return socket_error; + } + sock_named = + Socket::Create(protocol, /*child_processes_inherit=*/false, error); + if (error.Fail()) { + fprintf(stderr, "Failed to create socket: %s", error.AsCString()); + return socket_error; + } + error = sock_named->Listen(hostname, backlog); + if (error.Fail()) { + printf("Failed to listen: %s\n", error.AsCString()); + return socket_error; + } + socket_id = hostname; } + if (socket_file) { - error = - save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file); + error = save_socket_id_to_file(socket_id, socket_file); if (error.Fail()) { fprintf(stderr, "failed to write socket id to %s: %s\n", socket_file.GetPath().c_str(), error.AsCString()); return 1; } } - GDBRemoteCommunicationServerPlatform platform( - acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme()); + lldb_private::Args gdb_inferior_arguments(inferior_arguments); + GDBRemoteCommunicationServerPlatform platform(protocol, gdbserver_port); if (port_offset > 0) platform.SetPortOffset(port_offset); - do { - const bool children_inherit_accept_socket = true; - Connection *conn = nullptr; - error = acceptor_up->Accept(children_inherit_accept_socket, conn); - if (error.Fail()) { - WithColor::error() << error.AsCString() << '\n'; - exit(socket_error); + if (protocol == Socket::ProtocolTcp) { + llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> platform_handles = + sock_platform->Accept( + *g_main_loop, + [progname, gdbserver_port, port_offset, inferior_arguments, + log_file, log_channels](std::unique_ptr<TCPSocket> sock_up) { + // If not running as a server, this process will not accept + // connections while a connection is active. + if (g_server || g_single_pid == LLDB_INVALID_PROCESS_ID) { + printf("Platform connection established.\n"); + Status error = spawn_process( + progname, sock_up.get(), gdbserver_port, port_offset, + inferior_arguments, log_file, log_channels); + if (error.Fail()) { + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString()); + WithColor::error() + << "spawn_process failed: " << error.AsCString() << "\n"; + if (!g_server) { + g_terminate = true; + g_main_loop->AddPendingCallback( + [](MainLoopBase &loop) { loop.RequestTermination(); }); + } + } + } + sock_up.reset(); + }); + if (!platform_handles) { + printf("Failed to accept platform: %s\n", + llvm::toString(platform_handles.takeError()).c_str()); + return socket_error; } - printf("Connection established.\n"); - if (g_server) { - std::optional<uint16_t> available_port; - { - std::lock_guard<std::mutex> guard(gdbserver_portmap_mutex); - auto port = gdbserver_portmap.GetNextAvailablePort(); - if (port) - available_port = *port; - else - llvm::consumeError(port.takeError()); - } - if (!available_port) { - fprintf(stderr, - "no available gdbserver port for connection - dropping...\n"); - } else { - const Socket *conn_socket = - static_cast<const Socket *>(conn->GetReadObject().get()); - error = - spawn_process(progname, conn_socket, *available_port, port_offset, - inferior_arguments, log_file, log_channels); - if (error.Fail()) { - { - - std::lock_guard<std::mutex> guard(gdbserver_portmap_mutex); - gdbserver_portmap.FreePort(*available_port); - } - LLDB_LOGF(GetLog(LLDBLog::Platform), "spawn_process failed: %s", - error.AsCString()); - WithColor::error() - << "spawn_process failed: " << error.AsCString() << "\n"; - } - } - // Parent doesn't need a connection to the lldb client - delete conn; - - // Parent will continue to listen for new connections. - continue; - } else { - // If not running as a server, this process will not accept - // connections while a connection is active. - acceptor_up.reset(); - - // When not running in server mode, use all available ports - platform.SetPortMap(std::move(gdbserver_portmap)); + llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> gdb_handles = + sock_gdb->Accept(*g_main_loop, [&platform, &gdb_inferior_arguments]( + std::unique_ptr<TCPSocket> sock_up) { + printf("Gdb connection established.\n"); + Status error; + Log *log = GetLog(LLDBLog::Platform); + SharedSocket shared_socket(sock_up.get(), error); + if (error.Success()) { + lldb::pid_t child_pid = LLDB_INVALID_PROCESS_ID; + std::string socket_name; + error = platform.LaunchGDBServer(gdb_inferior_arguments, child_pid, + socket_name, + shared_socket.GetSendableFD()); + if (error.Success() && child_pid != LLDB_INVALID_PROCESS_ID) { + error = shared_socket.CompleteSending(child_pid); + if (error.Success()) { + // Use gdb inferior arguments once. + gdb_inferior_arguments.Clear(); + } else { + Host::Kill(child_pid, SIGTERM); + LLDB_LOGF(log, "gdbserver CompleteSending failed: %s", + error.AsCString()); + } + } + } else + LLDB_LOGF(log, "gdbserver SharedSocket failed: %s", + error.AsCString()); + + sock_up.reset(); + }); + if (!gdb_handles) { + printf("Failed to accept gdb: %s\n", + llvm::toString(gdb_handles.takeError()).c_str()); + return socket_error; } - platform.SetConnection(std::unique_ptr<Connection>(conn)); + do { + g_main_loop->Run(); + } while (!g_terminate); + + gdb_handles->clear(); + platform_handles->clear(); + + g_main_loop.reset(); + sock_gdb.reset(); + sock_platform.reset(); ---------------- slydiman wrote:
I have added platform_tcp() and platform_named() and placed handles inside a block. https://github.com/llvm/llvm-project/pull/104238 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits