diff --git a/lldb/docs/use/qemu-testing.rst b/lldb/docs/use/qemu-testing.rst index 6e282141864cc..51a30b11717a8 100644 --- a/lldb/docs/use/qemu-testing.rst +++ b/lldb/docs/use/qemu-testing.rst @@ -172,6 +172,7 @@ forwarded for this to work. .. note:: These options are used to create a "port map" within ``lldb-server``. - Unfortunately this map is not shared across all the processes it may create, + Unfortunately this map is not cleaned up on Windows on connection close, and across a few uses you may run out of valid ports. To work around this, restart the platform every so often, especially after running a set of tests. + This is tracked here: https://github.com/llvm/llvm-project/issues/90923 diff --git a/lldb/tools/lldb-server/lldb-platform.cpp b/lldb/tools/lldb-server/lldb-platform.cpp index 3e126584eb25b..cfd0a3797d810 100644 --- a/lldb/tools/lldb-server/lldb-platform.cpp +++ b/lldb/tools/lldb-server/lldb-platform.cpp @@ -282,17 +282,12 @@ int main_platform(int argc, char *argv[]) { } } - do { - GDBRemoteCommunicationServerPlatform platform( - acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme()); - - if (port_offset > 0) - platform.SetPortOffset(port_offset); - - if (!gdbserver_portmap.empty()) { - platform.SetPortMap(std::move(gdbserver_portmap)); - } + GDBRemoteCommunicationServerPlatform platform( + acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme()); + 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); @@ -301,13 +296,37 @@ int main_platform(int argc, char *argv[]) { exit(socket_error); } printf("Connection established.\n"); + if (g_server) { // Collect child zombie processes. #if !defined(_WIN32) - while (waitpid(-1, nullptr, WNOHANG) > 0) - ; + ::pid_t waitResult; + while ((waitResult = waitpid(-1, nullptr, WNOHANG)) > 0) { + // waitResult is the child pid + gdbserver_portmap.FreePortForProcess(waitResult); + } #endif - if (fork()) { + // TODO: Clean up portmap for Windows when children die + // See https://github.com/llvm/llvm-project/issues/90923 + + // After collecting zombie ports, get the next available + GDBRemoteCommunicationServerPlatform::PortMap portmap_for_child; + llvm::Expected available_port = + gdbserver_portmap.GetNextAvailablePort(); + if (available_port) + portmap_for_child.AllowPort(*available_port); + else { + llvm::consumeError(available_port.takeError()); + fprintf(stderr, + "no available gdbserver port for connection - dropping...\n"); + delete conn; + continue; + } + platform.SetPortMap(std::move(portmap_for_child)); + + auto childPid = fork(); + if (childPid) { + gdbserver_portmap.AssociatePortWithProcess(*available_port, childPid); // Parent doesn't need a connection to the lldb client delete conn; @@ -323,7 +342,11 @@ int main_platform(int argc, char *argv[]) { // 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)); } + platform.SetConnection(std::unique_ptr(conn)); if (platform.IsConnected()) {