| """Test that we get thread names when interrupting a process.""" | |
| import time | |
| import lldb | |
| from lldbsuite.test.decorators import * | |
| from lldbsuite.test.lldbtest import * | |
| from lldbsuite.test import lldbutil | |
| class TestInterruptThreadNames(TestBase): | |
| NO_DEBUG_INFO_TESTCASE = True | |
| @requireDarwin | |
| @add_test_categories(["pyapi"]) | |
| def test_with_python_api(self): | |
| """Test that we get thread names when interrupting a process.""" | |
| self.build() | |
| exe = self.getBuildArtifact("a.out") | |
| target = self.dbg.CreateTarget(exe) | |
| self.assertTrue(target, VALID_TARGET) | |
| launch_info = target.GetLaunchInfo() | |
| error = lldb.SBError() | |
| self.dbg.SetAsync(True) | |
| process = target.Launch(launch_info, error) | |
| self.assertTrue(process, PROCESS_IS_VALID) | |
| listener = self.dbg.GetListener() | |
| broadcaster = process.GetBroadcaster() | |
| rc = broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged) | |
| self.assertNotEqual(rc, 0, "Unable to add listener to process") | |
| self.assertTrue( | |
| self.wait_for_running(process, listener), | |
| "Check that process is up and running", | |
| ) | |
| inferior_set_up = self.wait_until_program_setup_complete(process, listener) | |
| # Check that the program was able to create its threads within the allotted time | |
| self.assertTrue(inferior_set_up.IsValid()) | |
| self.assertEqual(inferior_set_up.GetValueAsSigned(), 1) | |
| self.check_number_of_threads(process) | |
| main_thread = lldb.SBThread() | |
| second_thread = lldb.SBThread() | |
| third_thread = lldb.SBThread() | |
| for idx in range(0, process.GetNumThreads()): | |
| t = process.GetThreadAtIndex(idx) | |
| if t.GetName() == "main thread": | |
| main_thread = t | |
| if t.GetName() == "second thread": | |
| second_thread = t | |
| if t.GetName() == "third thread": | |
| third_thread = t | |
| self.check_expected_threads_present(main_thread, second_thread, third_thread) | |
| process.Kill() | |
| # The process will set a global variable 'threads_up_and_running' to 1 when | |
| # it has has completed its setup. Sleep for one second, pause the program, | |
| # check to see if the global has that value, and continue if it does not. | |
| def wait_until_program_setup_complete(self, process, listener): | |
| inferior_set_up = lldb.SBValue() | |
| retry = 5 | |
| while retry > 0: | |
| arch = self.getArchitecture() | |
| # when running the testsuite against a remote arm device, it may take | |
| # a little longer for the process to start up. Use a "can't possibly take | |
| # longer than this" value. | |
| if arch == "arm64" or arch == "armv7": | |
| time.sleep(10) | |
| else: | |
| time.sleep(1) | |
| process.SendAsyncInterrupt() | |
| self.assertTrue( | |
| self.wait_for_stop(process, listener), "Check that process is paused" | |
| ) | |
| inferior_set_up = process.GetTarget().CreateValueFromExpression( | |
| "threads_up_and_running", "threads_up_and_running" | |
| ) | |
| if inferior_set_up.IsValid() and inferior_set_up.GetValueAsSigned() == 1: | |
| retry = 0 | |
| else: | |
| process.Continue() | |
| retry = retry - 1 | |
| return inferior_set_up | |
| # Listen to the process events until we get an event saying that the process is | |
| # running. Retry up to five times in case we get other events that are not | |
| # what we're looking for. | |
| def wait_for_running(self, process, listener): | |
| retry_count = 5 | |
| if process.GetState() == lldb.eStateRunning: | |
| return True | |
| while retry_count > 0: | |
| event = lldb.SBEvent() | |
| listener.WaitForEvent(2, event) | |
| if event.GetType() == lldb.SBProcess.eBroadcastBitStateChanged: | |
| if process.GetState() == lldb.eStateRunning: | |
| return True | |
| retry_count = retry_count - 1 | |
| return False | |
| # Listen to the process events until we get an event saying the process is | |
| # stopped. Retry up to five times in case we get other events that we are | |
| # not looking for. | |
| def wait_for_stop(self, process, listener): | |
| retry_count = 5 | |
| if ( | |
| process.GetState() == lldb.eStateStopped | |
| or process.GetState() == lldb.eStateCrashed | |
| or process.GetState() == lldb.eStateDetached | |
| or process.GetState() == lldb.eStateExited | |
| ): | |
| return True | |
| while retry_count > 0: | |
| event = lldb.SBEvent() | |
| listener.WaitForEvent(2, event) | |
| if event.GetType() == lldb.SBProcess.eBroadcastBitStateChanged: | |
| if ( | |
| process.GetState() == lldb.eStateStopped | |
| or process.GetState() == lldb.eStateCrashed | |
| or process.GetState() == lldb.eStateDetached | |
| or process.GetState() == lldb.eStateExited | |
| ): | |
| return True | |
| if ( | |
| process.GetState() == lldb.eStateCrashed | |
| or process.GetState() == lldb.eStateDetached | |
| or process.GetState() == lldb.eStateExited | |
| ): | |
| return False | |
| retry_count = retry_count - 1 | |
| return False | |
| def check_number_of_threads(self, process): | |
| self.assertEqual( | |
| process.GetNumThreads(), | |
| 3, | |
| "Check that the process has three threads when sitting at the stopper() breakpoint", | |
| ) | |
| def check_expected_threads_present(self, main_thread, second_thread, third_thread): | |
| self.assertTrue( | |
| main_thread.IsValid() | |
| and second_thread.IsValid() | |
| and third_thread.IsValid(), | |
| "Got all three expected threads", | |
| ) |