diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -117,6 +117,7 @@ bool m_thread_suffix_supported = false; bool m_list_threads_in_stop_reply = false; bool m_non_stop = false; + bool m_disabling_non_stop = false; std::deque m_stdio_notification_queue; std::deque m_stop_notification_queue; 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 @@ -1919,6 +1919,20 @@ bool force_synchronous) { Log *log = GetLog(LLDBLog::Process); + if (m_disabling_non_stop) { + // Check if we are waiting for any more processes to stop. If we are, + // do not send the OK response yet. + for (const auto &it : m_debugged_processes) { + if (it.second.process_up->IsRunning()) + return PacketResult::Success; + } + + // If all expected processes were stopped after a QNonStop:0 request, + // send the OK response. + m_disabling_non_stop = false; + return SendOKResponse(); + } + switch (process_state) { case eStateAttaching: case eStateLaunching: @@ -3903,12 +3917,33 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_QNonStop( StringExtractorGDBRemote &packet) { + Log *log = GetLog(LLDBLog::Process); + StringRef packet_str{packet.GetStringRef()}; assert(packet_str.startswith("QNonStop:")); packet_str.consume_front("QNonStop:"); if (packet_str == "0") { + for (auto &process_it : m_debugged_processes) { + if (process_it.second.process_up->IsRunning()) { + assert(m_non_stop); + Status error = process_it.second.process_up->Interrupt(); + if (error.Fail()) { + LLDB_LOG(log, + "while disabling nonstop, failed to halt process {0}: {1}", + process_it.first, error); + return SendErrorResponse(0x41); + } + // we must not send stop reasons after QNonStop + m_disabling_non_stop = true; + } + } + m_stdio_notification_queue.clear(); + m_stop_notification_queue.clear(); m_non_stop = false; - // TODO: stop all threads + // If we are stopping anything, defer sending the OK response until we're + // done. + if (m_disabling_non_stop) + return PacketResult::Success; } else if (packet_str == "1") { m_non_stop = true; } else diff --git a/lldb/test/API/tools/lldb-server/TestNonStop.py b/lldb/test/API/tools/lldb-server/TestNonStop.py --- a/lldb/test/API/tools/lldb-server/TestNonStop.py +++ b/lldb/test/API/tools/lldb-server/TestNonStop.py @@ -362,3 +362,33 @@ "send packet: $OK#00", ], True) self.expect_gdbremote_sequence() + + @add_test_categories(["llgs"]) + def test_leave_nonstop(self): + self.build() + self.set_inferior_startup_launch() + procs = self.prep_debug_monitor_and_inferior( + inferior_args=["thread:new", "thread:new", "stop", "sleep:15"]) + self.test_sequence.add_log_lines( + ["read packet: $QNonStop:1#00", + "send packet: $OK#00", + # stop is used to synchronize starting threads + "read packet: $c#63", + "send packet: $OK#00", + {"direction": "send", "regex": "%Stop:T.*"}, + "read packet: $c#63", + "send packet: $OK#00", + # verify that the threads are running now + "read packet: $?#00", + "send packet: $OK#00", + "read packet: $QNonStop:0#00", + "send packet: $OK#00", + # we should issue some random request now to verify that the stub + # did not send stop reasons -- we may verify whether notification + # queue was cleared while at it + "read packet: $vStopped#00", + "send packet: $Eff#00", + "read packet: $?#00", + {"direction": "send", "regex": "[$]T.*"}, + ], True) + self.expect_gdbremote_sequence()