diff --git a/lldb/test/API/tools/lldb-vscode/correct-thread/Makefile b/lldb/test/API/tools/lldb-vscode/correct-thread/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/tools/lldb-vscode/correct-thread/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +CFLAGS_EXTRAS := -lpthread + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-vscode/correct-thread/TestVSCode_correct_thread.py b/lldb/test/API/tools/lldb-vscode/correct-thread/TestVSCode_correct_thread.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/tools/lldb-vscode/correct-thread/TestVSCode_correct_thread.py @@ -0,0 +1,47 @@ +""" +Test lldb-vscode setBreakpoints request +""" + +from __future__ import print_function + +import unittest2 +import vscode +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbvscode_testcase + + +class TestVSCode_correct_thread(lldbvscode_testcase.VSCodeTestCaseBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipIfWindows + @skipIfRemote + def test_correct_thread(self): + ''' + Tests that the correct thread is selected if we continue from + a thread that goes away and hit a breakpoint in another thread. + In this case, the selected thread should be the thread that + just hit the breakpoint, and not the first thread in the list. + ''' + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + source = 'main.c' + breakpoint_line = line_number(source, '// break here') + lines = [breakpoint_line] + # Set breakpoint in the thread function + breakpoint_ids = self.set_source_breakpoints(source, lines) + self.assertEqual(len(breakpoint_ids), len(lines), + "expect correct number of breakpoints") + self.continue_to_breakpoints(breakpoint_ids) + # We're now stopped at the breakpoint in the first thread, thread #2. + # Continue to join the first thread and hit the breakpoint in the + # second thread, thread #3. + self.vscode.request_continue() + stopped_event = self.vscode.wait_for_stopped() + # Verify that the description is the relevant breakpoint, + # preserveFocusHint is False and threadCausedFocus is True + self.assertTrue(stopped_event[0]['body']['description'].startswith('breakpoint %s.' % breakpoint_ids[0])) + self.assertFalse(stopped_event[0]['body']['preserveFocusHint']) + self.assertTrue(stopped_event[0]['body']['threadCausedFocus']) diff --git a/lldb/test/API/tools/lldb-vscode/correct-thread/main.c b/lldb/test/API/tools/lldb-vscode/correct-thread/main.c new file mode 100644 --- /dev/null +++ b/lldb/test/API/tools/lldb-vscode/correct-thread/main.c @@ -0,0 +1,23 @@ +#include +#include + +int state_var; + +void *thread (void *in) +{ + state_var++; // break here + return NULL; +} + +int main(int argc, char **argv) +{ + pthread_t t1, t2; + + pthread_create(&t1, NULL, *thread, NULL); + pthread_join(t1, NULL); + pthread_create(&t2, NULL, *thread, NULL); + pthread_join(t2, NULL); + + printf("state_var is %d\n", state_var); + return 0; +} diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp --- a/lldb/tools/lldb-vscode/lldb-vscode.cpp +++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -232,13 +232,17 @@ // set it as the focus thread if below if needed. lldb::tid_t first_tid_with_reason = LLDB_INVALID_THREAD_ID; uint32_t num_threads_with_reason = 0; + bool focus_thread_exists = false; for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); const lldb::tid_t tid = thread.GetThreadID(); const bool has_reason = ThreadHasStopReason(thread); // If the focus thread doesn't have a stop reason, clear the thread ID - if (tid == g_vsc.focus_tid && !has_reason) - g_vsc.focus_tid = LLDB_INVALID_THREAD_ID; + if (tid == g_vsc.focus_tid) { + focus_thread_exists = true; + if (!has_reason) + g_vsc.focus_tid = LLDB_INVALID_THREAD_ID; + } if (has_reason) { ++num_threads_with_reason; if (first_tid_with_reason == LLDB_INVALID_THREAD_ID) @@ -246,10 +250,10 @@ } } - // We will have cleared g_vsc.focus_tid if he focus thread doesn't - // have a stop reason, so if it was cleared, or wasn't set, then set the - // focus thread to the first thread with a stop reason. - if (g_vsc.focus_tid == LLDB_INVALID_THREAD_ID) + // We will have cleared g_vsc.focus_tid if he focus thread doesn't have + // a stop reason, so if it was cleared, or wasn't set, or doesn't exist, + // then set the focus thread to the first thread with a stop reason. + if (!focus_thread_exists || g_vsc.focus_tid == LLDB_INVALID_THREAD_ID) g_vsc.focus_tid = first_tid_with_reason; // If no threads stopped with a reason, then report the first one so