[Lldb-commits] [lldb] fed25dd - [LLDB][GUI] Expand selected thread tree item by default

Greg Clayton via lldb-commits lldb-commits at lists.llvm.org
Mon Jul 26 14:21:07 PDT 2021


Author: Omar Emara
Date: 2021-07-26T14:20:50-07:00
New Revision: fed25ddc1c3de59aa1de27e95b349f86896ccb79

URL: https://github.com/llvm/llvm-project/commit/fed25ddc1c3de59aa1de27e95b349f86896ccb79
DIFF: https://github.com/llvm/llvm-project/commit/fed25ddc1c3de59aa1de27e95b349f86896ccb79.diff

LOG: [LLDB][GUI] Expand selected thread tree item by default

This patch expands the tree item that corresponds to the selected thread
by default in the Threads window. Additionally, the tree root item is
always expanded, which is the process in the Threads window.

Reviewed By: clayborg

Differential Revision: https://reviews.llvm.org/D100243

Added: 
    lldb/test/API/commands/gui/expand-threads-tree/Makefile
    lldb/test/API/commands/gui/expand-threads-tree/TestGuiExpandThreadsTree.py
    lldb/test/API/commands/gui/expand-threads-tree/main.c

Modified: 
    lldb/source/Core/IOHandlerCursesGUI.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp
index b54511d2cebb5..e664ac1ba4bd4 100644
--- a/lldb/source/Core/IOHandlerCursesGUI.cpp
+++ b/lldb/source/Core/IOHandlerCursesGUI.cpp
@@ -3361,8 +3361,13 @@ class TreeDelegate {
 
   virtual void TreeDelegateDrawTreeItem(TreeItem &item, Window &window) = 0;
   virtual void TreeDelegateGenerateChildren(TreeItem &item) = 0;
+  virtual void TreeDelegateUpdateSelection(TreeItem &root, int &selection_index,
+                                           TreeItem *&selected_item) {
+    return;
+  }
   virtual bool TreeDelegateItemSelected(
       TreeItem &item) = 0; // Return true if we need to update views
+  virtual bool TreeDelegateExpandRootByDefault() { return false; }
 };
 
 typedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
@@ -3372,7 +3377,10 @@ class TreeItem {
   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) {
+    if (m_parent == nullptr)
+      m_is_expanded = m_delegate.TreeDelegateExpandRootByDefault();
+  }
 
   TreeItem &operator=(const TreeItem &rhs) {
     if (this != &rhs) {
@@ -3601,6 +3609,8 @@ class TreeWindowDelegate : public WindowDelegate {
       const int num_visible_rows = NumVisibleRows();
       m_num_rows = 0;
       m_root.CalculateRowIndexes(m_num_rows);
+      m_delegate_sp->TreeDelegateUpdateSelection(m_root, m_selected_row_idx,
+                                                 m_selected_item);
 
       // If we unexpanded while having something selected our total number of
       // rows is less than the num visible rows, then make sure we show all the
@@ -3902,7 +3912,7 @@ class ThreadsTreeDelegate : public TreeDelegate {
 public:
   ThreadsTreeDelegate(Debugger &debugger)
       : TreeDelegate(), m_thread_delegate_sp(), m_debugger(debugger),
-        m_stop_id(UINT32_MAX) {
+        m_stop_id(UINT32_MAX), m_update_selection(false) {
     FormatEntity::Parse("process ${process.id}{, name = ${process.name}}",
                         m_format);
   }
@@ -3930,6 +3940,7 @@ class ThreadsTreeDelegate : public TreeDelegate {
 
   void TreeDelegateGenerateChildren(TreeItem &item) override {
     ProcessSP process_sp = GetProcess();
+    m_update_selection = false;
     if (process_sp && process_sp->IsAlive()) {
       StateType state = process_sp->GetState();
       if (StateIsStoppedState(state, true)) {
@@ -3938,6 +3949,7 @@ class ThreadsTreeDelegate : public TreeDelegate {
           return; // Children are already up to date
 
         m_stop_id = stop_id;
+        m_update_selection = true;
 
         if (!m_thread_delegate_sp) {
           // Always expand the thread item the first time we show it
@@ -3949,11 +3961,15 @@ class ThreadsTreeDelegate : public TreeDelegate {
         TreeItem t(&item, *m_thread_delegate_sp, false);
         ThreadList &threads = process_sp->GetThreadList();
         std::lock_guard<std::recursive_mutex> 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;
       }
@@ -3961,12 +3977,42 @@ class ThreadsTreeDelegate : public TreeDelegate {
     item.ClearChildren();
   }
 
+  void TreeDelegateUpdateSelection(TreeItem &root, int &selection_index,
+                                   TreeItem *&selected_item) override {
+    if (!m_update_selection)
+      return;
+
+    ProcessSP process_sp = GetProcess();
+    if (!(process_sp && process_sp->IsAlive()))
+      return;
+
+    StateType state = process_sp->GetState();
+    if (!StateIsStoppedState(state, true))
+      return;
+
+    ThreadList &threads = process_sp->GetThreadList();
+    std::lock_guard<std::recursive_mutex> guard(threads.GetMutex());
+    ThreadSP selected_thread = threads.GetSelectedThread();
+    size_t num_threads = threads.GetSize();
+    for (size_t i = 0; i < num_threads; ++i) {
+      ThreadSP thread = threads.GetThreadAtIndex(i);
+      if (selected_thread->GetID() == thread->GetID()) {
+        selected_item = &root[i][thread->GetSelectedFrameIndex()];
+        selection_index = selected_item->GetRowIndex();
+        return;
+      }
+    }
+  }
+
   bool TreeDelegateItemSelected(TreeItem &item) override { return false; }
 
+  bool TreeDelegateExpandRootByDefault() override { return true; }
+
 protected:
   std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp;
   Debugger &m_debugger;
   uint32_t m_stop_id;
+  bool m_update_selection;
   FormatEntity::Entry m_format;
 };
 

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
index 0000000000000..0c11fbdd8669c
--- /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
index 0000000000000..0e095661d3ec8
--- /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
index 0000000000000..32e6d17c799a6
--- /dev/null
+++ b/lldb/test/API/commands/gui/expand-threads-tree/main.c
@@ -0,0 +1,10 @@
+#include <pthread.h>
+
+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;
+}


        


More information about the lldb-commits mailing list