Skip to content

Commit df93c4f

Browse files
committed
Remove some raciness from the TestProcessAttach.test_run_then_attach_wait_interrupt
command. We were reading the command output right after sending the interrupt, but sometimes that wasn't long enough for the command result text to have been emitted. I added a poll for the state change to eStateExited, and then added a bit more sleep to give the command a chance to complete.
1 parent 7705342 commit df93c4f

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

lldb/test/API/commands/process/attach/TestProcessAttach.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55

66
import os
7+
import threading
8+
import time
79
import lldb
810
import shutil
911
from lldbsuite.test.decorators import *
@@ -128,3 +130,84 @@ def tearDown(self):
128130

129131
# Call super's tearDown().
130132
TestBase.tearDown(self)
133+
134+
def test_run_then_attach_wait_interrupt(self):
135+
# Test that having run one process doesn't cause us to be unable
136+
# to interrupt a subsequent attach attempt.
137+
self.build()
138+
exe = self.getBuildArtifact(exe_name)
139+
140+
target = lldbutil.run_to_breakpoint_make_target(self, exe_name, True)
141+
launch_info = target.GetLaunchInfo()
142+
launch_info.SetArguments(["q"], True)
143+
error = lldb.SBError()
144+
target.Launch(launch_info, error)
145+
self.assertSuccess(error, "Launched a process")
146+
self.assertState(target.process.state, lldb.eStateExited, "and it exited.")
147+
148+
# Okay now we've run a process, try to attach/wait to something
149+
# and make sure that we can interrupt that.
150+
151+
options = lldb.SBCommandInterpreterRunOptions()
152+
options.SetPrintResults(True)
153+
options.SetEchoCommands(False)
154+
155+
self.stdin_path = self.getBuildArtifact("stdin.txt")
156+
157+
with open(self.stdin_path, "w") as input_handle:
158+
input_handle.write("process attach -w -n noone_would_use_this_name\nquit")
159+
160+
# Python will close the file descriptor if all references
161+
# to the filehandle object lapse, so we need to keep one
162+
# around.
163+
self.filehandle = open(self.stdin_path, "r")
164+
self.dbg.SetInputFileHandle(self.filehandle, False)
165+
166+
# No need to track the output
167+
self.stdout_path = self.getBuildArtifact("stdout.txt")
168+
self.out_filehandle = open(self.stdout_path, "w")
169+
self.dbg.SetOutputFileHandle(self.out_filehandle, False)
170+
self.dbg.SetErrorFileHandle(self.out_filehandle, False)
171+
172+
n_errors, quit_req, crashed = self.dbg.RunCommandInterpreter(
173+
True, True, options, 0, False, False)
174+
175+
while 1:
176+
time.sleep(1)
177+
if target.process.state == lldb.eStateAttaching:
178+
break
179+
180+
self.dbg.DispatchInputInterrupt()
181+
self.dbg.DispatchInputInterrupt()
182+
183+
# cycle waiting for the process state to change before trying
184+
# to read the command output. I don't want to spin forever.
185+
counter = 0
186+
got_exit = False
187+
while counter < 20:
188+
if target.process.state == lldb.eStateExited:
189+
got_exit = True
190+
break
191+
counter += 1
192+
time.sleep(1)
193+
194+
self.assertTrue(got_exit, "The process never switched to eStateExited")
195+
# Even if the state has flipped, we still need to wait for the
196+
# command to complete to see the result. We don't have a way to
197+
# synchronize on "command completed" right now, but sleeping just
198+
# a bit should be enough, all that's left is passing this error
199+
# result to the command, and printing it to the debugger output.
200+
time.sleep(1)
201+
202+
self.out_filehandle.flush()
203+
reader = open(self.stdout_path, "r")
204+
results = reader.readlines()
205+
found_result = False
206+
for line in results:
207+
if "Cancelled async attach" in line:
208+
found_result = True
209+
break
210+
if not found_result:
211+
print(f"Results: {results}")
212+
213+
self.assertTrue(found_result, "Found async error in results")

0 commit comments

Comments
 (0)