1dbbed971SJim Ingham""" 2dbbed971SJim InghamMake sure that we handle an expression on a thread, if 3dbbed971SJim Inghamthe thread exits while the expression is running. 4dbbed971SJim Ingham""" 5dbbed971SJim Ingham 6dbbed971SJim Inghamimport lldb 7dbbed971SJim Inghamfrom lldbsuite.test.decorators import * 8dbbed971SJim Inghamimport lldbsuite.test.lldbutil as lldbutil 9dbbed971SJim Inghamfrom lldbsuite.test.lldbtest import * 10dbbed971SJim Ingham 11dbbed971SJim Ingham 12*2238dcc3SJonas Devlieghereclass TestExitDuringExpression(TestBase): 13dbbed971SJim Ingham NO_DEBUG_INFO_TESTCASE = True 14dbbed971SJim Ingham 15dbbed971SJim Ingham @skipIfWindows 167dd76cccSMuhammad Omair Javaid @skipIf(oslist=["linux"], archs=["arm", "aarch64"], bugnumber="llvm.org/pr48414") 17266c90feSMichał Górny @expectedFailureAll(oslist=["freebsd"], bugnumber="llvm.org/pr48414") 1899562332SMichał Górny @expectedFailureNetBSD 19dbbed971SJim Ingham def test_exit_before_one_thread_unwind(self): 20dbbed971SJim Ingham """Test the case where we exit within the one thread timeout""" 21dbbed971SJim Ingham self.exiting_expression_test(True, True) 22dbbed971SJim Ingham 23dbbed971SJim Ingham @skipIfWindows 2428058d4cSMuhammad Omair Javaid @skipIf(oslist=["linux"], archs=["arm", "aarch64"], bugnumber="llvm.org/pr48414") 25266c90feSMichał Górny @expectedFailureAll(oslist=["freebsd"], bugnumber="llvm.org/pr48414") 2699562332SMichał Górny @expectedFailureNetBSD 27dbbed971SJim Ingham def test_exit_before_one_thread_no_unwind(self): 28dbbed971SJim Ingham """Test the case where we exit within the one thread timeout""" 29dbbed971SJim Ingham self.exiting_expression_test(True, False) 30dbbed971SJim Ingham 31dbbed971SJim Ingham @skipIfWindows 32dbbed971SJim Ingham def test_exit_after_one_thread_unwind(self): 33dbbed971SJim Ingham """Test the case where we exit within the one thread timeout""" 34dbbed971SJim Ingham self.exiting_expression_test(False, True) 35dbbed971SJim Ingham 36dbbed971SJim Ingham @skipIfWindows 37dbbed971SJim Ingham def test_exit_after_one_thread_no_unwind(self): 38dbbed971SJim Ingham """Test the case where we exit within the one thread timeout""" 39dbbed971SJim Ingham self.exiting_expression_test(False, False) 40dbbed971SJim Ingham 41dbbed971SJim Ingham def setUp(self): 42dbbed971SJim Ingham TestBase.setUp(self) 43dbbed971SJim Ingham self.main_source_file = lldb.SBFileSpec("main.c") 44dbbed971SJim Ingham self.build() 45dbbed971SJim Ingham 46dbbed971SJim Ingham def exiting_expression_test(self, before_one_thread_timeout, unwind): 47dbbed971SJim Ingham """function_to_call sleeps for g_timeout microseconds, then calls pthread_exit. 48dbbed971SJim Ingham This test calls function_to_call with an overall timeout of 500 49dbbed971SJim Ingham microseconds, and a one_thread_timeout as passed in. 50dbbed971SJim Ingham It also sets unwind_on_exit for the call to the unwind passed in. 51dbbed971SJim Ingham This allows you to have the thread exit either before the one thread 52dbbed971SJim Ingham timeout is passed.""" 53dbbed971SJim Ingham 54*2238dcc3SJonas Devlieghere (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 55*2238dcc3SJonas Devlieghere self, "Break here and cause the thread to exit", self.main_source_file 56*2238dcc3SJonas Devlieghere ) 57dbbed971SJim Ingham 58dbbed971SJim Ingham # We'll continue to this breakpoint after running our expression: 59*2238dcc3SJonas Devlieghere return_bkpt = target.BreakpointCreateBySourceRegex( 60*2238dcc3SJonas Devlieghere "Break here to make sure the thread exited", self.main_source_file 61*2238dcc3SJonas Devlieghere ) 62dbbed971SJim Ingham frame = thread.frames[0] 63dbbed971SJim Ingham tid = thread.GetThreadID() 64dbbed971SJim Ingham # Find the timeout: 65dbbed971SJim Ingham var_options = lldb.SBVariablesOptions() 66dbbed971SJim Ingham var_options.SetIncludeArguments(False) 67dbbed971SJim Ingham var_options.SetIncludeLocals(False) 68dbbed971SJim Ingham var_options.SetIncludeStatics(True) 69dbbed971SJim Ingham 70dbbed971SJim Ingham value_list = frame.GetVariables(var_options) 71dbbed971SJim Ingham g_timeout = value_list.GetFirstValueByName("g_timeout") 72dbbed971SJim Ingham self.assertTrue(g_timeout.IsValid(), "Found g_timeout") 73dbbed971SJim Ingham 74dbbed971SJim Ingham error = lldb.SBError() 75dbbed971SJim Ingham timeout_value = g_timeout.GetValueAsUnsigned(error) 76779bbbf2SDave Lee self.assertSuccess(error, "Couldn't get timeout value") 77dbbed971SJim Ingham 78dbbed971SJim Ingham one_thread_timeout = 0 79*2238dcc3SJonas Devlieghere if before_one_thread_timeout: 80dbbed971SJim Ingham one_thread_timeout = timeout_value * 2 81dbbed971SJim Ingham else: 82dbbed971SJim Ingham one_thread_timeout = int(timeout_value / 2) 83dbbed971SJim Ingham 84dbbed971SJim Ingham options = lldb.SBExpressionOptions() 85dbbed971SJim Ingham options.SetUnwindOnError(unwind) 86dbbed971SJim Ingham options.SetOneThreadTimeoutInMicroSeconds(one_thread_timeout) 87dbbed971SJim Ingham options.SetTimeoutInMicroSeconds(4 * timeout_value) 88dbbed971SJim Ingham 89dbbed971SJim Ingham result = frame.EvaluateExpression("function_to_call()", options) 90dbbed971SJim Ingham 91dbbed971SJim Ingham # Make sure the thread actually exited: 92dbbed971SJim Ingham thread = process.GetThreadByID(tid) 93dbbed971SJim Ingham self.assertFalse(thread.IsValid(), "The thread exited") 94dbbed971SJim Ingham 95dbbed971SJim Ingham # Make sure the expression failed: 96dbbed971SJim Ingham self.assertFalse(result.GetError().Success(), "Expression failed.") 97dbbed971SJim Ingham 98dbbed971SJim Ingham # Make sure we can keep going: 99dbbed971SJim Ingham threads = lldbutil.continue_to_breakpoint(process, return_bkpt) 100dbbed971SJim Ingham if not threads: 101dbbed971SJim Ingham self.fail("didn't get any threads back after continuing") 102dbbed971SJim Ingham 103dbbed971SJim Ingham self.assertEqual(len(threads), 1, "One thread hit our breakpoint") 104dbbed971SJim Ingham thread = threads[0] 105dbbed971SJim Ingham frame = thread.frames[0] 106dbbed971SJim Ingham # Now get the return value, if we successfully caused the thread to exit 107dbbed971SJim Ingham # it should be 10, not 20. 108dbbed971SJim Ingham ret_val = frame.FindVariable("ret_val") 109779bbbf2SDave Lee self.assertSuccess(ret_val.GetError(), "Found ret_val") 110dbbed971SJim Ingham ret_val_value = ret_val.GetValueAsSigned(error) 111779bbbf2SDave Lee self.assertSuccess(error, "Got ret_val's value") 112dbbed971SJim Ingham self.assertEqual(ret_val_value, 10, "We put the right value in ret_val") 113