forked from OSchip/llvm-project
[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 llvm-svn: 357426
This commit is contained in:
parent
66d7eb9704
commit
4665aca8ca
|
@ -52,11 +52,11 @@ def dump_memory(base_addr, data, num_per_line, outfile):
|
||||||
|
|
||||||
def read_packet(f, verbose=False, trace_file=None):
|
def read_packet(f, verbose=False, trace_file=None):
|
||||||
'''Decode a JSON packet that starts with the content length and is
|
'''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")
|
line = f.readline().decode("utf-8")
|
||||||
if len(line) == 0:
|
if len(line) == 0:
|
||||||
return None
|
return None # EOF.
|
||||||
|
|
||||||
# Watch for line that starts with the prefix
|
# Watch for line that starts with the prefix
|
||||||
prefix = 'Content-Length: '
|
prefix = 'Content-Length: '
|
||||||
|
@ -91,10 +91,10 @@ def read_packet_thread(vs_comm):
|
||||||
done = False
|
done = False
|
||||||
while not done:
|
while not done:
|
||||||
packet = read_packet(vs_comm.recv, trace_file=vs_comm.trace_file)
|
packet = read_packet(vs_comm.recv, trace_file=vs_comm.trace_file)
|
||||||
if packet:
|
# `packet` will be `None` on EOF. We want to pass it down to
|
||||||
done = not vs_comm.handle_recv_packet(packet)
|
# handle_recv_packet anyway so the main thread can handle unexpected
|
||||||
else:
|
# termination of lldb-vscode and stop waiting for new packets.
|
||||||
done = True
|
done = not vs_comm.handle_recv_packet(packet)
|
||||||
|
|
||||||
|
|
||||||
class DebugCommunication(object):
|
class DebugCommunication(object):
|
||||||
|
@ -146,6 +146,12 @@ class DebugCommunication(object):
|
||||||
self.output_condition.release()
|
self.output_condition.release()
|
||||||
return output
|
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):
|
def handle_recv_packet(self, packet):
|
||||||
'''Called by the read thread that is waiting for all incoming packets
|
'''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
|
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
|
indicate a new packet is available. Returns True if the caller
|
||||||
should keep calling this function for more packets.
|
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
|
# Check the packet to see if is an event packet
|
||||||
keepGoing = True
|
keepGoing = True
|
||||||
packet_type = packet['type']
|
packet_type = packet['type']
|
||||||
|
@ -191,10 +202,7 @@ class DebugCommunication(object):
|
||||||
elif packet_type == 'response':
|
elif packet_type == 'response':
|
||||||
if packet['command'] == 'disconnect':
|
if packet['command'] == 'disconnect':
|
||||||
keepGoing = False
|
keepGoing = False
|
||||||
self.recv_condition.acquire()
|
self.enqueue_recv_packet(packet)
|
||||||
self.recv_packets.append(packet)
|
|
||||||
self.recv_condition.notify()
|
|
||||||
self.recv_condition.release()
|
|
||||||
return keepGoing
|
return keepGoing
|
||||||
|
|
||||||
def send_packet(self, command_dict, set_sequence=True):
|
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
|
function will wait for the packet to arrive and return it when
|
||||||
it does.'''
|
it does.'''
|
||||||
while True:
|
while True:
|
||||||
self.recv_condition.acquire()
|
try:
|
||||||
packet = None
|
self.recv_condition.acquire()
|
||||||
while True:
|
packet = None
|
||||||
for (i, curr_packet) in enumerate(self.recv_packets):
|
while True:
|
||||||
packet_type = curr_packet['type']
|
for (i, curr_packet) in enumerate(self.recv_packets):
|
||||||
if filter_type is None or packet_type in filter_type:
|
if not curr_packet:
|
||||||
if (filter_event is None or
|
raise EOFError
|
||||||
(packet_type == 'event' and
|
packet_type = curr_packet['type']
|
||||||
curr_packet['event'] in filter_event)):
|
if filter_type is None or packet_type in filter_type:
|
||||||
packet = self.recv_packets.pop(i)
|
if (filter_event is None or
|
||||||
break
|
(packet_type == 'event' and
|
||||||
if packet:
|
curr_packet['event'] in filter_event)):
|
||||||
break
|
packet = self.recv_packets.pop(i)
|
||||||
# Sleep until packet is received
|
break
|
||||||
len_before = len(self.recv_packets)
|
if packet:
|
||||||
self.recv_condition.wait(timeout)
|
break
|
||||||
len_after = len(self.recv_packets)
|
# Sleep until packet is received
|
||||||
if len_before == len_after:
|
len_before = len(self.recv_packets)
|
||||||
return None # Timed out
|
self.recv_condition.wait(timeout)
|
||||||
self.recv_condition.release()
|
len_after = len(self.recv_packets)
|
||||||
return packet
|
if len_before == len_after:
|
||||||
|
return None # Timed out
|
||||||
|
return packet
|
||||||
|
except EOFError:
|
||||||
|
return None
|
||||||
|
finally:
|
||||||
|
self.recv_condition.release()
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue