[Lldb-commits] [lldb] r357426 - [lldb-vscode] Add logic to handle EOF when reading from lldb-vscode stdout.

Jorge Gorbe Moya via lldb-commits lldb-commits at lists.llvm.org
Mon Apr 1 13:37:22 PDT 2019


Author: jgorbe
Date: Mon Apr  1 13:37:22 2019
New Revision: 357426

URL: http://llvm.org/viewvc/llvm-project?rev=357426&view=rev
Log:
[lldb-vscode] Add logic to handle EOF when reading from lldb-vscode stdout.

Summary:
This change prevents the lldb-vscode test harness from hanging up waiting for
new messages when the lldb-vscode subprocess crashes.

Now, when an EOF from the subprocess pipe is detected we enqueue a `None` packet
in the received packets list. Then, during the message processing loop, we can
use this `None` packet to tell apart the case where lldb-vscode has terminated
unexpectedly from the normal situation where no pending messages means blocking
and waiting for more data.

I believe this should be enough to fix the issues with these tests hanging on
multiple platforms. Once this lands, I'll prepare and test a separate change
removing the @skipIfLinux annotations.

Reviewers: clayborg, zturner

Subscribers: lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D59849

Modified:
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py

Modified: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py?rev=357426&r1=357425&r2=357426&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py Mon Apr  1 13:37:22 2019
@@ -52,11 +52,11 @@ def dump_memory(base_addr, data, num_per
 
 def read_packet(f, verbose=False, trace_file=None):
     '''Decode a JSON packet that starts with the content length and is
-       followed by the JSON bytes from a file 'f'
+       followed by the JSON bytes from a file 'f'. Returns None on EOF.
     '''
     line = f.readline().decode("utf-8")
     if len(line) == 0:
-        return None
+        return None  # EOF.
 
     # Watch for line that starts with the prefix
     prefix = 'Content-Length: '
@@ -91,10 +91,10 @@ def read_packet_thread(vs_comm):
     done = False
     while not done:
         packet = read_packet(vs_comm.recv, trace_file=vs_comm.trace_file)
-        if packet:
-            done = not vs_comm.handle_recv_packet(packet)
-        else:
-            done = True
+        # `packet` will be `None` on EOF. We want to pass it down to
+        # handle_recv_packet anyway so the main thread can handle unexpected
+        # termination of lldb-vscode and stop waiting for new packets.
+        done = not vs_comm.handle_recv_packet(packet)
 
 
 class DebugCommunication(object):
@@ -146,6 +146,12 @@ class DebugCommunication(object):
         self.output_condition.release()
         return output
 
+    def enqueue_recv_packet(self, packet):
+        self.recv_condition.acquire()
+        self.recv_packets.append(packet)
+        self.recv_condition.notify()
+        self.recv_condition.release()
+
     def handle_recv_packet(self, packet):
         '''Called by the read thread that is waiting for all incoming packets
            to store the incoming packet in "self.recv_packets" in a thread safe
@@ -153,6 +159,11 @@ class DebugCommunication(object):
            indicate a new packet is available. Returns True if the caller
            should keep calling this function for more packets.
         '''
+        # If EOF, notify the read thread by enqueing a None.
+        if not packet:
+            self.enqueue_recv_packet(None)
+            return False
+
         # Check the packet to see if is an event packet
         keepGoing = True
         packet_type = packet['type']
@@ -191,10 +202,7 @@ class DebugCommunication(object):
         elif packet_type == 'response':
             if packet['command'] == 'disconnect':
                 keepGoing = False
-        self.recv_condition.acquire()
-        self.recv_packets.append(packet)
-        self.recv_condition.notify()
-        self.recv_condition.release()
+        self.enqueue_recv_packet(packet)
         return keepGoing
 
     def send_packet(self, command_dict, set_sequence=True):
@@ -222,27 +230,33 @@ class DebugCommunication(object):
            function will wait for the packet to arrive and return it when
            it does.'''
         while True:
-            self.recv_condition.acquire()
-            packet = None
-            while True:
-                for (i, curr_packet) in enumerate(self.recv_packets):
-                    packet_type = curr_packet['type']
-                    if filter_type is None or packet_type in filter_type:
-                        if (filter_event is None or
-                            (packet_type == 'event' and
-                             curr_packet['event'] in filter_event)):
-                            packet = self.recv_packets.pop(i)
-                            break
-                if packet:
-                    break
-                # Sleep until packet is received
-                len_before = len(self.recv_packets)
-                self.recv_condition.wait(timeout)
-                len_after = len(self.recv_packets)
-                if len_before == len_after:
-                    return None  # Timed out
-            self.recv_condition.release()
-            return packet
+            try:
+                self.recv_condition.acquire()
+                packet = None
+                while True:
+                    for (i, curr_packet) in enumerate(self.recv_packets):
+                        if not curr_packet:
+                            raise EOFError
+                        packet_type = curr_packet['type']
+                        if filter_type is None or packet_type in filter_type:
+                            if (filter_event is None or
+                                (packet_type == 'event' and
+                                 curr_packet['event'] in filter_event)):
+                                packet = self.recv_packets.pop(i)
+                                break
+                    if packet:
+                        break
+                    # Sleep until packet is received
+                    len_before = len(self.recv_packets)
+                    self.recv_condition.wait(timeout)
+                    len_after = len(self.recv_packets)
+                    if len_before == len_after:
+                        return None  # Timed out
+                return packet
+            except EOFError:
+                return None
+            finally:
+                self.recv_condition.release()
 
         return None
 




More information about the lldb-commits mailing list