Author: Michał Górny Date: 2022-07-15T21:50:39+02:00 New Revision: 09531ede6d5622da68941902072dbca517d31318
URL: https://github.com/llvm/llvm-project/commit/09531ede6d5622da68941902072dbca517d31318 DIFF: https://github.com/llvm/llvm-project/commit/09531ede6d5622da68941902072dbca517d31318.diff LOG: [lldb] [llgs] Improve stdio forwarding in multiprocess+nonstop Enable stdio forwarding when nonstop mode is enabled, and disable it once it is disabled. This makes it possible to cleanly handle stdio forwarding while running multiple processes in non-stop mode. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.llvm.org/D128932 Added: Modified: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py lldb/test/API/tools/lldb-server/main.cpp Removed: ################################################################################ diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index be789bdf7da5..5804c13fe7b6 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1113,14 +1113,16 @@ void GDBRemoteCommunicationServerLLGS::ProcessStateChanged( SendProcessOutput(); // Then stop the forwarding, so that any late output (see llvm.org/pr25652) // does not interfere with our protocol. - StopSTDIOForwarding(); + if (!m_non_stop) + StopSTDIOForwarding(); HandleInferiorState_Stopped(process); break; case StateType::eStateExited: // Same as above SendProcessOutput(); - StopSTDIOForwarding(); + if (!m_non_stop) + StopSTDIOForwarding(); HandleInferiorState_Exited(process); break; @@ -1425,7 +1427,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process); - StopSTDIOForwarding(); + if (!m_non_stop) + StopSTDIOForwarding(); if (m_debugged_processes.empty()) { LLDB_LOG(log, "No debugged process found."); @@ -1451,7 +1454,8 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vKill( StringExtractorGDBRemote &packet) { - StopSTDIOForwarding(); + if (!m_non_stop) + StopSTDIOForwarding(); packet.SetFilePos(6); // vKill; uint32_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16); @@ -3524,7 +3528,8 @@ GDBRemoteCommunicationServerLLGS::Handle_vRun( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process); - StopSTDIOForwarding(); + if (!m_non_stop) + StopSTDIOForwarding(); lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; @@ -3923,6 +3928,8 @@ GDBRemoteCommunicationServerLLGS::Handle_QNonStop( assert(packet_str.startswith("QNonStop:")); packet_str.consume_front("QNonStop:"); if (packet_str == "0") { + if (m_non_stop) + StopSTDIOForwarding(); for (auto &process_it : m_debugged_processes) { if (process_it.second.process_up->IsRunning()) { assert(m_non_stop); @@ -3945,6 +3952,8 @@ GDBRemoteCommunicationServerLLGS::Handle_QNonStop( if (m_disabling_non_stop) return PacketResult::Success; } else if (packet_str == "1") { + if (!m_non_stop) + StartSTDIOForwarding(); m_non_stop = true; } else return SendErrorResponse(Status("Invalid QNonStop packet")); @@ -4238,9 +4247,10 @@ void GDBRemoteCommunicationServerLLGS::SetEnabledExtensions( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::SendContinueSuccessResponse() { - // TODO: how to handle forwarding in non-stop mode? + if (m_non_stop) + return SendOKResponse(); StartSTDIOForwarding(); - return m_non_stop ? SendOKResponse() : PacketResult::Success; + return PacketResult::Success; } void GDBRemoteCommunicationServerLLGS::AppendThreadIDToResponse( diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py index 7ba376485513..0868c32bdd32 100644 --- a/lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py +++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py @@ -112,3 +112,33 @@ def test_c_interspersed_nonstop(self): def test_vCont_interspersed_nonstop(self): self.resume_one_test(run_order=["parent", "child", "parent", "child"], use_vCont=True, nonstop=True) + + @add_test_categories(["fork"]) + def test_c_both_nonstop(self): + lock1 = self.getBuildArtifact("lock1") + lock2 = self.getBuildArtifact("lock2") + parent_pid, parent_tid, child_pid, child_tid = ( + self.start_fork_test(["fork", "process:sync:" + lock1, "print-pid", + "process:sync:" + lock2, "stop"], + nonstop=True)) + + self.test_sequence.add_log_lines([ + "read packet: $Hcp{}.{}#00".format(parent_pid, parent_tid), + "send packet: $OK#00", + "read packet: $c#00", + "send packet: $OK#00", + "read packet: $Hcp{}.{}#00".format(child_pid, child_tid), + "send packet: $OK#00", + "read packet: $c#00", + "send packet: $OK#00", + {"direction": "send", "regex": "%Stop:T.*"}, + # see the comment in TestNonStop.py, test_stdio + "read packet: $vStdio#00", + "read packet: $vStdio#00", + "send packet: $OK#00", + ], True) + ret = self.expect_gdbremote_sequence() + self.assertIn("PID: {}".format(int(parent_pid, 16)).encode(), + ret["O_content"]) + self.assertIn("PID: {}".format(int(child_pid, 16)).encode(), + ret["O_content"]) diff --git a/lldb/test/API/tools/lldb-server/main.cpp b/lldb/test/API/tools/lldb-server/main.cpp index 21e46ef4e1b6..5d33ee6e1b0b 100644 --- a/lldb/test/API/tools/lldb-server/main.cpp +++ b/lldb/test/API/tools/lldb-server/main.cpp @@ -224,6 +224,8 @@ int main(int argc, char **argv) { int return_value = 0; #if !defined(_WIN32) + bool is_child = false; + // Set the signal handler. sig_t sig_result = signal(SIGALRM, signal_handler); if (sig_result == SIG_ERR) { @@ -324,10 +326,32 @@ int main(int argc, char **argv) { func_p(); #if !defined(_WIN32) && !defined(TARGET_OS_WATCH) && !defined(TARGET_OS_TV) } else if (arg == "fork") { - assert (fork() != -1); + pid_t fork_pid = fork(); + assert(fork_pid != -1); + is_child = fork_pid == 0; } else if (arg == "vfork") { if (vfork() == 0) _exit(0); + } else if (consume_front(arg, "process:sync:")) { + // this is only valid after fork + const char *filenames[] = {"parent", "child"}; + std::string my_file = arg + "." + filenames[is_child]; + std::string other_file = arg + "." + filenames[!is_child]; + + // indicate that we're ready + FILE *f = fopen(my_file.c_str(), "w"); + assert(f); + fclose(f); + + // wait for the other process to be ready + for (int i = 0; i < 5; ++i) { + f = fopen(other_file.c_str(), "r"); + if (f) + break; + std::this_thread::sleep_for(std::chrono::milliseconds(125 * (1<<i))); + } + assert(f); + fclose(f); #endif } else if (consume_front(arg, "thread:new")) { std::promise<void> promise; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits