diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1113,14 +1113,16 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 --- a/lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py +++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py @@ -112,3 +112,33 @@ 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 --- a/lldb/test/API/tools/lldb-server/main.cpp +++ b/lldb/test/API/tools/lldb-server/main.cpp @@ -224,6 +224,8 @@ 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 @@ 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< promise;