diff --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp --- a/lldb/source/Core/IOHandlerCursesGUI.cpp +++ b/lldb/source/Core/IOHandlerCursesGUI.cpp @@ -1619,7 +1619,12 @@ TreeItem(TreeItem *parent, TreeDelegate &delegate, bool might_have_children) : m_parent(parent), m_delegate(delegate), m_user_data(nullptr), m_identifier(0), m_row_idx(-1), m_children(), - m_might_have_children(might_have_children), m_is_expanded(false) {} + m_might_have_children(might_have_children), m_is_expanded(false) { + // Expand root tree items by default. + if (m_parent == nullptr) { + m_is_expanded = true; + } + } TreeItem &operator=(const TreeItem &rhs) { if (this != &rhs) { @@ -2196,11 +2201,16 @@ TreeItem t(&item, *m_thread_delegate_sp, false); ThreadList &threads = process_sp->GetThreadList(); std::lock_guard guard(threads.GetMutex()); + ThreadSP selected_thread = threads.GetSelectedThread(); size_t num_threads = threads.GetSize(); item.Resize(num_threads, t); for (size_t i = 0; i < num_threads; ++i) { - item[i].SetIdentifier(threads.GetThreadAtIndex(i)->GetID()); + ThreadSP thread = threads.GetThreadAtIndex(i); + item[i].SetIdentifier(thread->GetID()); item[i].SetMightHaveChildren(true); + if (selected_thread->GetID() == thread->GetID()) { + item[i].Expand(); + } } return; } diff --git a/lldb/test/API/commands/gui/expand-threads-tree/Makefile b/lldb/test/API/commands/gui/expand-threads-tree/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/gui/expand-threads-tree/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c +ENABLE_THREADS := YES +include Makefile.rules diff --git a/lldb/test/API/commands/gui/expand-threads-tree/TestGuiExpandThreadsTree.py b/lldb/test/API/commands/gui/expand-threads-tree/TestGuiExpandThreadsTree.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/gui/expand-threads-tree/TestGuiExpandThreadsTree.py @@ -0,0 +1,55 @@ +""" +Test the 'gui' default thread tree expansion. +The root process tree item and the tree item corresponding to the selected +thread should be expanded by default. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test.lldbpexpect import PExpectTest + +class TestGuiExpandThreadsTree(PExpectTest): + + mydir = TestBase.compute_mydir(__file__) + + # PExpect uses many timeouts internally and doesn't play well + # under ASAN on a loaded machine.. + @skipIfAsan + @skipIfCursesSupportMissing + def test_gui(self): + self.build() + + self.launch(executable=self.getBuildArtifact("a.out"), dimensions=(100,500)) + self.expect("breakpoint set -r thread_start_routine", substrs=["Breakpoint 1", "address ="]) + self.expect("run", substrs=["stop reason ="]) + + escape_key = chr(27).encode() + + # Start the GUI and close the welcome window. + self.child.sendline("gui") + self.child.send(escape_key) + self.child.expect_exact("Threads") + + # The thread running thread_start_routine should be expanded. + self.child.expect_exact("frame #0: thread_start_routine") + + # Exit GUI. + self.child.send(escape_key) + self.expect_prompt() + + # Select the main thread. + self.child.sendline("thread select 1") + + # Start the GUI. + self.child.sendline("gui") + self.child.expect_exact("Threads") + + # The main thread should be expanded. + self.child.expect("frame #\d+: main") + + # Quit the GUI + self.child.send(escape_key) + + self.expect_prompt() + self.quit() diff --git a/lldb/test/API/commands/gui/expand-threads-tree/main.c b/lldb/test/API/commands/gui/expand-threads-tree/main.c new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/gui/expand-threads-tree/main.c @@ -0,0 +1,10 @@ +#include + +void *thread_start_routine(void *arg) { return NULL; } + +int main() { + pthread_t thread; + pthread_create(&thread, NULL, thread_start_routine, NULL); + pthread_join(thread, NULL); + return 0; +}