Skip to content

Commit fed25dd

Browse files
OmarEmaraDevclayborg
authored andcommitted
[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
1 parent c285a11 commit fed25dd

File tree

4 files changed

+117
-3
lines changed

4 files changed

+117
-3
lines changed

lldb/source/Core/IOHandlerCursesGUI.cpp

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3361,8 +3361,13 @@ class TreeDelegate {
33613361

33623362
virtual void TreeDelegateDrawTreeItem(TreeItem &item, Window &window) = 0;
33633363
virtual void TreeDelegateGenerateChildren(TreeItem &item) = 0;
3364+
virtual void TreeDelegateUpdateSelection(TreeItem &root, int &selection_index,
3365+
TreeItem *&selected_item) {
3366+
return;
3367+
}
33643368
virtual bool TreeDelegateItemSelected(
33653369
TreeItem &item) = 0; // Return true if we need to update views
3370+
virtual bool TreeDelegateExpandRootByDefault() { return false; }
33663371
};
33673372

33683373
typedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
@@ -3372,7 +3377,10 @@ class TreeItem {
33723377
TreeItem(TreeItem *parent, TreeDelegate &delegate, bool might_have_children)
33733378
: m_parent(parent), m_delegate(delegate), m_user_data(nullptr),
33743379
m_identifier(0), m_row_idx(-1), m_children(),
3375-
m_might_have_children(might_have_children), m_is_expanded(false) {}
3380+
m_might_have_children(might_have_children), m_is_expanded(false) {
3381+
if (m_parent == nullptr)
3382+
m_is_expanded = m_delegate.TreeDelegateExpandRootByDefault();
3383+
}
33763384

33773385
TreeItem &operator=(const TreeItem &rhs) {
33783386
if (this != &rhs) {
@@ -3601,6 +3609,8 @@ class TreeWindowDelegate : public WindowDelegate {
36013609
const int num_visible_rows = NumVisibleRows();
36023610
m_num_rows = 0;
36033611
m_root.CalculateRowIndexes(m_num_rows);
3612+
m_delegate_sp->TreeDelegateUpdateSelection(m_root, m_selected_row_idx,
3613+
m_selected_item);
36043614

36053615
// If we unexpanded while having something selected our total number of
36063616
// rows is less than the num visible rows, then make sure we show all the
@@ -3902,7 +3912,7 @@ class ThreadsTreeDelegate : public TreeDelegate {
39023912
public:
39033913
ThreadsTreeDelegate(Debugger &debugger)
39043914
: TreeDelegate(), m_thread_delegate_sp(), m_debugger(debugger),
3905-
m_stop_id(UINT32_MAX) {
3915+
m_stop_id(UINT32_MAX), m_update_selection(false) {
39063916
FormatEntity::Parse("process ${process.id}{, name = ${process.name}}",
39073917
m_format);
39083918
}
@@ -3930,6 +3940,7 @@ class ThreadsTreeDelegate : public TreeDelegate {
39303940

39313941
void TreeDelegateGenerateChildren(TreeItem &item) override {
39323942
ProcessSP process_sp = GetProcess();
3943+
m_update_selection = false;
39333944
if (process_sp && process_sp->IsAlive()) {
39343945
StateType state = process_sp->GetState();
39353946
if (StateIsStoppedState(state, true)) {
@@ -3938,6 +3949,7 @@ class ThreadsTreeDelegate : public TreeDelegate {
39383949
return; // Children are already up to date
39393950

39403951
m_stop_id = stop_id;
3952+
m_update_selection = true;
39413953

39423954
if (!m_thread_delegate_sp) {
39433955
// Always expand the thread item the first time we show it
@@ -3949,24 +3961,58 @@ class ThreadsTreeDelegate : public TreeDelegate {
39493961
TreeItem t(&item, *m_thread_delegate_sp, false);
39503962
ThreadList &threads = process_sp->GetThreadList();
39513963
std::lock_guard<std::recursive_mutex> guard(threads.GetMutex());
3964+
ThreadSP selected_thread = threads.GetSelectedThread();
39523965
size_t num_threads = threads.GetSize();
39533966
item.Resize(num_threads, t);
39543967
for (size_t i = 0; i < num_threads; ++i) {
3955-
item[i].SetIdentifier(threads.GetThreadAtIndex(i)->GetID());
3968+
ThreadSP thread = threads.GetThreadAtIndex(i);
3969+
item[i].SetIdentifier(thread->GetID());
39563970
item[i].SetMightHaveChildren(true);
3971+
if (selected_thread->GetID() == thread->GetID())
3972+
item[i].Expand();
39573973
}
39583974
return;
39593975
}
39603976
}
39613977
item.ClearChildren();
39623978
}
39633979

3980+
void TreeDelegateUpdateSelection(TreeItem &root, int &selection_index,
3981+
TreeItem *&selected_item) override {
3982+
if (!m_update_selection)
3983+
return;
3984+
3985+
ProcessSP process_sp = GetProcess();
3986+
if (!(process_sp && process_sp->IsAlive()))
3987+
return;
3988+
3989+
StateType state = process_sp->GetState();
3990+
if (!StateIsStoppedState(state, true))
3991+
return;
3992+
3993+
ThreadList &threads = process_sp->GetThreadList();
3994+
std::lock_guard<std::recursive_mutex> guard(threads.GetMutex());
3995+
ThreadSP selected_thread = threads.GetSelectedThread();
3996+
size_t num_threads = threads.GetSize();
3997+
for (size_t i = 0; i < num_threads; ++i) {
3998+
ThreadSP thread = threads.GetThreadAtIndex(i);
3999+
if (selected_thread->GetID() == thread->GetID()) {
4000+
selected_item = &root[i][thread->GetSelectedFrameIndex()];
4001+
selection_index = selected_item->GetRowIndex();
4002+
return;
4003+
}
4004+
}
4005+
}
4006+
39644007
bool TreeDelegateItemSelected(TreeItem &item) override { return false; }
39654008

4009+
bool TreeDelegateExpandRootByDefault() override { return true; }
4010+
39664011
protected:
39674012
std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp;
39684013
Debugger &m_debugger;
39694014
uint32_t m_stop_id;
4015+
bool m_update_selection;
39704016
FormatEntity::Entry m_format;
39714017
};
39724018

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
C_SOURCES := main.c
2+
ENABLE_THREADS := YES
3+
include Makefile.rules
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""
2+
Test the 'gui' default thread tree expansion.
3+
The root process tree item and the tree item corresponding to the selected
4+
thread should be expanded by default.
5+
"""
6+
7+
import lldb
8+
from lldbsuite.test.decorators import *
9+
from lldbsuite.test.lldbtest import *
10+
from lldbsuite.test.lldbpexpect import PExpectTest
11+
12+
class TestGuiExpandThreadsTree(PExpectTest):
13+
14+
mydir = TestBase.compute_mydir(__file__)
15+
16+
# PExpect uses many timeouts internally and doesn't play well
17+
# under ASAN on a loaded machine..
18+
@skipIfAsan
19+
@skipIfCursesSupportMissing
20+
def test_gui(self):
21+
self.build()
22+
23+
self.launch(executable=self.getBuildArtifact("a.out"), dimensions=(100,500))
24+
self.expect("breakpoint set -r thread_start_routine", substrs=["Breakpoint 1", "address ="])
25+
self.expect("run", substrs=["stop reason ="])
26+
27+
escape_key = chr(27).encode()
28+
29+
# Start the GUI and close the welcome window.
30+
self.child.sendline("gui")
31+
self.child.send(escape_key)
32+
self.child.expect_exact("Threads")
33+
34+
# The thread running thread_start_routine should be expanded.
35+
self.child.expect_exact("frame #0: thread_start_routine")
36+
37+
# Exit GUI.
38+
self.child.send(escape_key)
39+
self.expect_prompt()
40+
41+
# Select the main thread.
42+
self.child.sendline("thread select 1")
43+
44+
# Start the GUI.
45+
self.child.sendline("gui")
46+
self.child.expect_exact("Threads")
47+
48+
# The main thread should be expanded.
49+
self.child.expect("frame #\d+: main")
50+
51+
# Quit the GUI
52+
self.child.send(escape_key)
53+
54+
self.expect_prompt()
55+
self.quit()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <pthread.h>
2+
3+
void *thread_start_routine(void *arg) { return NULL; }
4+
5+
int main() {
6+
pthread_t thread;
7+
pthread_create(&thread, NULL, thread_start_routine, NULL);
8+
pthread_join(thread, NULL);
9+
return 0;
10+
}

0 commit comments

Comments
 (0)