This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG1903f358bcc7: [lldb] [llgs] Send process output 
asynchronously in non-stop mode (authored by mgorny).
Herald added a project: LLDB.

Changed prior to commit:
  https://reviews.llvm.org/D128849?vs=441135&id=444993#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128849/new/

https://reviews.llvm.org/D128849

Files:
  lldb/include/lldb/Utility/StringExtractorGDBRemote.h
  lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
  lldb/source/Utility/StringExtractorGDBRemote.cpp
  lldb/test/API/tools/lldb-server/TestNonStop.py

Index: lldb/test/API/tools/lldb-server/TestNonStop.py
===================================================================
--- lldb/test/API/tools/lldb-server/TestNonStop.py
+++ lldb/test/API/tools/lldb-server/TestNonStop.py
@@ -296,3 +296,47 @@
     @add_test_categories(["llgs"])
     def test_vCont_then_partial_stop_run_both(self):
         self.vCont_then_partial_stop_test(True)
+
+    @add_test_categories(["llgs"])
+    def test_stdio(self):
+        self.build()
+        self.set_inferior_startup_launch()
+        # Since we can't easily ensure that lldb will send output in two parts,
+        # just put a stop in the middle.  Since we don't clear vStdio,
+        # the second message won't be delivered immediately.
+        self.prep_debug_monitor_and_inferior(
+            inferior_args=["message 1", "stop", "message 2"])
+        self.test_sequence.add_log_lines(
+            ["read packet: $QNonStop:1#00",
+             "send packet: $OK#00",
+             "read packet: $c#63",
+             "send packet: $OK#00",
+             {"direction": "send", "regex": r"^%Stop:T.*"},
+             "read packet: $vStopped#00",
+             "send packet: $OK#00",
+             "read packet: $c#63",
+             "send packet: $OK#00",
+             "send packet: %Stop:W00#00",
+             ], True)
+        ret = self.expect_gdbremote_sequence()
+        self.assertIn(ret["O_content"], b"message 1\r\n")
+
+        # Now, this is somewhat messy.  expect_gdbremote_sequence() will
+        # automatically consume output packets, so we just send vStdio,
+        # assume the first reply was consumed, send another one and expect
+        # a non-consumable "OK" reply.
+        self.reset_test_sequence()
+        self.test_sequence.add_log_lines(
+            ["read packet: $vStdio#00",
+             "read packet: $vStdio#00",
+             "send packet: $OK#00",
+             ], True)
+        ret = self.expect_gdbremote_sequence()
+        self.assertIn(ret["O_content"], b"message 2\r\n")
+
+        self.reset_test_sequence()
+        self.test_sequence.add_log_lines(
+            ["read packet: $vStopped#00",
+             "send packet: $OK#00",
+             ], True)
+        self.expect_gdbremote_sequence()
Index: lldb/source/Utility/StringExtractorGDBRemote.cpp
===================================================================
--- lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -380,6 +380,8 @@
         return eServerPacketType_vStopped;
       if (PACKET_MATCHES("vCtrlC"))
         return eServerPacketType_vCtrlC;
+      if (PACKET_MATCHES("vStdio"))
+        return eServerPacketType_vStdio;
       break;
 
     }
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ 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;
+  std::deque<std::string> m_stdio_notification_queue;
   std::deque<std::string> m_stop_notification_queue;
 
   NativeProcessProtocol::Extension m_extensions_supported = {};
@@ -247,6 +248,10 @@
 
   PacketResult Handle_QNonStop(StringExtractorGDBRemote &packet);
 
+  PacketResult HandleNotificationAck(std::deque<std::string> &queue);
+
+  PacketResult Handle_vStdio(StringExtractorGDBRemote &packet);
+
   PacketResult Handle_vStopped(StringExtractorGDBRemote &packet);
 
   PacketResult Handle_vCtrlC(StringExtractorGDBRemote &packet);
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -245,6 +245,9 @@
   RegisterMemberFunctionHandler(
       StringExtractorGDBRemote::eServerPacketType_QNonStop,
       &GDBRemoteCommunicationServerLLGS::Handle_QNonStop);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_vStdio,
+      &GDBRemoteCommunicationServerLLGS::Handle_vStdio);
   RegisterMemberFunctionHandler(
       StringExtractorGDBRemote::eServerPacketType_vStopped,
       &GDBRemoteCommunicationServerLLGS::Handle_vStopped);
@@ -1192,6 +1195,9 @@
   response.PutChar('O');
   response.PutBytesAsRawHex8(buffer, len);
 
+  if (m_non_stop)
+    return SendNotificationPacketNoLock("Stdio", m_stdio_notification_queue,
+                                        response.GetString());
   return SendPacketNoLock(response.GetString());
 }
 
@@ -3907,26 +3913,38 @@
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServerLLGS::Handle_vStopped(
-    StringExtractorGDBRemote &packet) {
+GDBRemoteCommunicationServerLLGS::HandleNotificationAck(
+    std::deque<std::string> &queue) {
   // Per the protocol, the first message put into the queue is sent
-  // immediately.  However, it remains the queue until the client ACKs
-  // it via vStopped -- then we pop it and send the next message.
-  // The process repeats until the last message in the queue is ACK-ed,
-  // in which case the vStopped packet sends an OK response.
-
-  if (m_stop_notification_queue.empty())
+  // immediately.  However, it remains the queue until the client ACKs it --
+  // then we pop it and send the next message.  The process repeats until
+  // the last message in the queue is ACK-ed, in which case the packet sends
+  // an OK response.
+  if (queue.empty())
     return SendErrorResponse(Status("No pending notification to ack"));
-  m_stop_notification_queue.pop_front();
-  if (!m_stop_notification_queue.empty())
-    return SendPacketNoLock(m_stop_notification_queue.front());
+  queue.pop_front();
+  if (!queue.empty())
+    return SendPacketNoLock(queue.front());
+  return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vStdio(
+    StringExtractorGDBRemote &packet) {
+  return HandleNotificationAck(m_stdio_notification_queue);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vStopped(
+    StringExtractorGDBRemote &packet) {
+  PacketResult ret = HandleNotificationAck(m_stop_notification_queue);
   // If this was the last notification and all the processes exited,
   // terminate the server.
-  if (m_debugged_processes.empty()) {
+  if (m_stop_notification_queue.empty() && m_debugged_processes.empty()) {
     m_exit_now = true;
     m_mainloop.RequestTermination();
   }
-  return SendOKResponse();
+  return ret;
 }
 
 GDBRemoteCommunication::PacketResult
Index: lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
+++ lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
@@ -79,26 +79,6 @@
         raise "Unknown packet type: {}".format(packet_type)
 
 
-def handle_O_packet(context, packet_contents, logger):
-    """Handle O packets."""
-    if (not packet_contents) or (len(packet_contents) < 1):
-        return False
-    elif packet_contents[0] != "O":
-        return False
-    elif packet_contents == "OK":
-        return False
-
-    new_text = gdbremote_hex_decode_string(packet_contents[1:])
-    context["O_content"] += new_text
-    context["O_count"] += 1
-
-    if logger:
-        logger.debug(
-            "text: new \"{}\", cumulative: \"{}\"".format(
-                new_text, context["O_content"]))
-
-    return True
-
 _STRIP_CHECKSUM_REGEX = re.compile(r'#[0-9a-fA-F]{2}$')
 _STRIP_COMMAND_PREFIX_REGEX = re.compile(r"^\$")
 _STRIP_COMMAND_PREFIX_M_REGEX = re.compile(r"^\$m")
@@ -859,19 +839,21 @@
     # Check if the pid is in the process_ids
     return pid in process_ids
 
+
 def _handle_output_packet_string(packet_contents):
-    if (not packet_contents) or (len(packet_contents) < 1):
+    # Warning: in non-stop mode, we currently handle only the first output
+    # packet since we'd need to inject vStdio packets
+    if not packet_contents.startswith((b"$O", b"%Stdio:O")):
         return None
-    elif packet_contents[0:1] != b"O":
-        return None
-    elif packet_contents == b"OK":
+    elif packet_contents == b"$OK":
         return None
     else:
-        return binascii.unhexlify(packet_contents[1:])
+        return binascii.unhexlify(packet_contents.partition(b"O")[2])
+
 
 class Server(object):
 
-    _GDB_REMOTE_PACKET_REGEX = re.compile(br'^[\$%]([^\#]*)#[0-9a-fA-F]{2}')
+    _GDB_REMOTE_PACKET_REGEX = re.compile(br'^([\$%][^\#]*)#[0-9a-fA-F]{2}')
 
     class ChecksumMismatch(Exception):
         pass
Index: lldb/include/lldb/Utility/StringExtractorGDBRemote.h
===================================================================
--- lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -179,6 +179,7 @@
     eServerPacketType_QNonStop,
     eServerPacketType_vStopped,
     eServerPacketType_vCtrlC,
+    eServerPacketType_vStdio,
   };
 
   ServerPacketType GetServerPacketType() const;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to