From 1851e9f3e04a5bf2d31e2235f4ecfc0c783d78d7 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 15 Oct 2009 04:40:33 +0000 Subject: [PATCH] * Added a stopped reason and additional info to Thread. ThreadHandler sets both accordingly. * The threads view shows the thread states now. Also added tool tips with additional info. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33591 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/debugger/ThreadHandler.cpp | 35 +++-- src/apps/debugger/ThreadHandler.h | 8 +- .../gui/team_window/ThreadListView.cpp | 134 +++++++++++++++--- .../debugger/gui/team_window/ThreadListView.h | 2 + src/apps/debugger/model/Thread.cpp | 7 +- src/apps/debugger/model/Thread.h | 23 ++- 6 files changed, 176 insertions(+), 33 deletions(-) diff --git a/src/apps/debugger/ThreadHandler.cpp b/src/apps/debugger/ThreadHandler.cpp index 475a02e000..e4b3709066 100644 --- a/src/apps/debugger/ThreadHandler.cpp +++ b/src/apps/debugger/ThreadHandler.cpp @@ -93,14 +93,16 @@ ThreadHandler::SetBreakpointAndRun(target_addr_t address) bool ThreadHandler::HandleThreadDebugged(ThreadDebuggedEvent* event) { - return _HandleThreadStopped(NULL); + return _HandleThreadStopped(NULL, THREAD_STOPPED_DEBUGGED); } bool ThreadHandler::HandleDebuggerCall(DebuggerCallEvent* event) { - return _HandleThreadStopped(NULL); + BString message; + fDebuggerInterface->ReadMemoryString(event->Message(), 1024, message); + return _HandleThreadStopped(NULL, THREAD_STOPPED_DEBUGGER_CALL, message); } @@ -155,14 +157,15 @@ ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event) } } - return _HandleThreadStopped(cpuState); + return _HandleThreadStopped(cpuState, THREAD_STOPPED_BREAKPOINT); } bool ThreadHandler::HandleWatchpointHit(WatchpointHitEvent* event) { - return _HandleThreadStopped(event->GetCpuState()); + return _HandleThreadStopped(event->GetCpuState(), + THREAD_STOPPED_WATCHPOINT); } @@ -175,14 +178,17 @@ ThreadHandler::HandleSingleStep(SingleStepEvent* event) return true; } - return _HandleThreadStopped(event->GetCpuState()); + return _HandleThreadStopped(event->GetCpuState(), + THREAD_STOPPED_SINGLE_STEP); } bool ThreadHandler::HandleExceptionOccurred(ExceptionOccurredEvent* event) { - return _HandleThreadStopped(NULL); + char buffer[256]; + get_debug_exception_string(event->Exception(), buffer, sizeof(buffer)); + return _HandleThreadStopped(NULL, THREAD_STOPPED_EXCEPTION, buffer); } @@ -209,8 +215,10 @@ ThreadHandler::HandleThreadAction(uint32 action) // When continuing the thread update thread state before actually issuing // the command, since we need to unlock. - if (action != MSG_THREAD_STOP) - _SetThreadState(THREAD_STATE_RUNNING, NULL); + if (action != MSG_THREAD_STOP) { + _SetThreadState(THREAD_STATE_RUNNING, NULL, THREAD_STOPPED_UNKNOWN, + BString()); + } locker.Unlock(); @@ -372,22 +380,25 @@ ThreadHandler::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info) bool -ThreadHandler::_HandleThreadStopped(CpuState* cpuState) +ThreadHandler::_HandleThreadStopped(CpuState* cpuState, uint32 stoppedReason, + const BString& stoppedReasonInfo) { _ClearContinuationState(); AutoLocker locker(fThread->GetTeam()); - _SetThreadState(THREAD_STATE_STOPPED, cpuState); + _SetThreadState(THREAD_STATE_STOPPED, cpuState, stoppedReason, + stoppedReasonInfo); return true; } void -ThreadHandler::_SetThreadState(uint32 state, CpuState* cpuState) +ThreadHandler::_SetThreadState(uint32 state, CpuState* cpuState, + uint32 stoppedReason, const BString& stoppedReasonInfo) { - fThread->SetState(state); + fThread->SetState(state, stoppedReason, stoppedReasonInfo); fThread->SetCpuState(cpuState); } diff --git a/src/apps/debugger/ThreadHandler.h b/src/apps/debugger/ThreadHandler.h index fe8ad48dcc..f78f069f37 100644 --- a/src/apps/debugger/ThreadHandler.h +++ b/src/apps/debugger/ThreadHandler.h @@ -64,10 +64,14 @@ private: virtual status_t GetImageDebugInfo(Image* image, ImageDebugInfo*& _info); - bool _HandleThreadStopped(CpuState* cpuState); + bool _HandleThreadStopped(CpuState* cpuState, + uint32 stoppedReason, + const BString& stoppedReasonInfo + = BString()); void _SetThreadState(uint32 state, - CpuState* cpuState); + CpuState* cpuState, uint32 stoppedReason, + const BString& stoppedReasonInfo); Statement* _GetStatementAtInstructionPointer( StackFrame* frame); diff --git a/src/apps/debugger/gui/team_window/ThreadListView.cpp b/src/apps/debugger/gui/team_window/ThreadListView.cpp index a7aa19d095..2bdb1a476e 100644 --- a/src/apps/debugger/gui/team_window/ThreadListView.cpp +++ b/src/apps/debugger/gui/team_window/ThreadListView.cpp @@ -6,8 +6,6 @@ #include "ThreadListView.h" -#include - #include #include @@ -15,6 +13,7 @@ #include #include +#include #include "table/TableColumns.h" @@ -27,22 +26,23 @@ enum { // #pragma mark - ThreadsTableModel -class ThreadListView::ThreadsTableModel : public TableModel { +class ThreadListView::ThreadsTableModel : public TableModel, + public TableToolTipProvider { public: ThreadsTableModel(Team* team) : fTeam(team) { - Update(); + Update(-1); } ~ThreadsTableModel() { fTeam = NULL; - Update(); + Update(-1); } - bool Update() + bool Update(thread_id threadID) { if (fTeam == NULL) { for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++) @@ -61,6 +61,8 @@ public: // remove no longer existing threads while (Thread* oldThread = fThreads.ItemAt(index)) { if (oldThread == newThread) { + if (threadID >= 0 && oldThread->ID() == threadID) + NotifyRowsChanged(index, 1); index++; newThread = it.Next(); } else { @@ -90,7 +92,7 @@ public: virtual int32 CountColumns() const { - return 2; + return 3; } virtual int32 CountRows() const @@ -109,6 +111,38 @@ public: value.SetTo(thread->ID()); return true; case 1: + { + switch (thread->State()) { + case THREAD_STATE_RUNNING: + value.SetTo("Running", B_VARIANT_DONT_COPY_DATA); + return true; + case THREAD_STATE_STOPPED: + break; + case THREAD_STATE_UNKNOWN: + default: + value.SetTo("?", B_VARIANT_DONT_COPY_DATA); + return true; + } + + // thread is stopped -- get the reason + switch (thread->StoppedReason()) { + case THREAD_STOPPED_DEBUGGER_CALL: + value.SetTo("Call", B_VARIANT_DONT_COPY_DATA); + return true; + case THREAD_STOPPED_EXCEPTION: + value.SetTo("Exception", B_VARIANT_DONT_COPY_DATA); + return true; + case THREAD_STOPPED_BREAKPOINT: + case THREAD_STOPPED_WATCHPOINT: + case THREAD_STOPPED_SINGLE_STEP: + case THREAD_STOPPED_DEBUGGED: + case THREAD_STOPPED_UNKNOWN: + default: + value.SetTo("Debugged", B_VARIANT_DONT_COPY_DATA); + return true; + } + } + case 2: value.SetTo(thread->Name(), B_VARIANT_DONT_COPY_DATA); return true; default: @@ -116,6 +150,57 @@ public: } } + virtual bool GetToolTipForTableCell(int32 rowIndex, int32 columnIndex, + BToolTip** _tip) + { + Thread* thread = fThreads.ItemAt(rowIndex); + if (thread == NULL) + return false; + + BString text; + text << "Thread: \"" << thread->Name() << "\" (" << thread->ID() + << ")\n"; + + switch (thread->State()) { + case THREAD_STATE_RUNNING: + text << "Running"; + break; + case THREAD_STATE_STOPPED: + { + switch (thread->StoppedReason()) { + case THREAD_STOPPED_DEBUGGER_CALL: + text << "Called debugger(): " + << thread->StoppedReasonInfo(); + break; + case THREAD_STOPPED_EXCEPTION: + text << "Caused exception: " + << thread->StoppedReasonInfo(); + break; + case THREAD_STOPPED_BREAKPOINT: + case THREAD_STOPPED_WATCHPOINT: + case THREAD_STOPPED_SINGLE_STEP: + case THREAD_STOPPED_DEBUGGED: + case THREAD_STOPPED_UNKNOWN: + default: + text << "Stopped for debugging"; + break; + } + break; + } + case THREAD_STATE_UNKNOWN: + default: + text << "Current State Unknown"; + break; + } + + BTextToolTip* tip = new(std::nothrow) BTextToolTip(text); + if (tip == NULL) + return false; + + *_tip = tip; + return true; + } + Thread* ThreadAt(int32 index) const { return fThreads.ItemAt(index); @@ -206,9 +291,14 @@ ThreadListView::MessageReceived(BMessage* message) { switch (message->what) { case MSG_SYNC_THREAD_LIST: - if (fThreadsTableModel != NULL) - fThreadsTableModel->Update(); + { + thread_id threadID; + if (message->FindInt32("thread", &threadID) != B_OK) + threadID = -1; + + fThreadsTableModel->Update(threadID); break; + } default: BGroupView::MessageReceived(message); break; @@ -230,6 +320,16 @@ ThreadListView::ThreadRemoved(const Team::ThreadEvent& event) } +void +ThreadListView::ThreadStateChanged(const Team::ThreadEvent& event) +{ + BMessage message(MSG_SYNC_THREAD_LIST); + message.AddInt32("thread", event.GetThread()->ID()); + + Looper()->PostMessage(&message, this); +} + + void ThreadListView::TableSelectionChanged(Table* table) { @@ -237,10 +337,8 @@ ThreadListView::TableSelectionChanged(Table* table) return; Thread* thread = NULL; - if (fThreadsTableModel != NULL) { - TableSelectionModel* selectionModel = table->SelectionModel(); - thread = fThreadsTableModel->ThreadAt(selectionModel->RowAt(0)); - } + TableSelectionModel* selectionModel = table->SelectionModel(); + thread = fThreadsTableModel->ThreadAt(selectionModel->RowAt(0)); fListener->ThreadSelectionChanged(thread); } @@ -253,17 +351,19 @@ ThreadListView::_Init() AddChild(fThreadsTable->ToView()); // columns - fThreadsTable->AddColumn(new Int32TableColumn(0, "ID", 40, 20, 1000, + fThreadsTable->AddColumn(new Int32TableColumn(0, "ID", 60, 20, 1000, B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT)); - fThreadsTable->AddColumn(new StringTableColumn(1, "Name", 80, 40, 1000, + fThreadsTable->AddColumn(new StringTableColumn(1, "State", 80, 40, 1000, + B_TRUNCATE_END, B_ALIGN_LEFT)); + fThreadsTable->AddColumn(new StringTableColumn(2, "Name", 200, 40, 1000, B_TRUNCATE_END, B_ALIGN_LEFT)); fThreadsTable->SetSelectionMode(B_SINGLE_SELECTION_LIST); fThreadsTable->AddTableListener(this); - fThreadsTableModel = new(std::nothrow) ThreadsTableModel(fTeam); + fThreadsTableModel = new ThreadsTableModel(fTeam); fThreadsTable->SetTableModel(fThreadsTableModel); - fThreadsTable->ResizeAllColumnsToPreferred(); + fThreadsTable->SetToolTipProvider(fThreadsTableModel); fTeam->AddListener(this); } diff --git a/src/apps/debugger/gui/team_window/ThreadListView.h b/src/apps/debugger/gui/team_window/ThreadListView.h index ac1e401d57..2d65b363b0 100644 --- a/src/apps/debugger/gui/team_window/ThreadListView.h +++ b/src/apps/debugger/gui/team_window/ThreadListView.h @@ -40,6 +40,8 @@ private: // Team::Listener virtual void ThreadAdded(const Team::ThreadEvent& event); virtual void ThreadRemoved(const Team::ThreadEvent& event); + virtual void ThreadStateChanged( + const Team::ThreadEvent& event); // TableListener virtual void TableSelectionChanged(Table* table); diff --git a/src/apps/debugger/model/Thread.cpp b/src/apps/debugger/model/Thread.cpp index 0f70e2a3d2..a0f4f9db37 100644 --- a/src/apps/debugger/model/Thread.cpp +++ b/src/apps/debugger/model/Thread.cpp @@ -5,6 +5,8 @@ #include "Thread.h" +#include + #include "CpuState.h" #include "StackTrace.h" #include "Team.h" @@ -15,6 +17,7 @@ Thread::Thread(Team* team, thread_id threadID) fTeam(team), fID(threadID), fState(THREAD_STATE_UNKNOWN), + fStoppedReason(THREAD_STOPPED_UNKNOWN), fCpuState(NULL), fStackTrace(NULL) { @@ -52,12 +55,14 @@ Thread::SetName(const BString& name) void -Thread::SetState(uint32 state) +Thread::SetState(uint32 state, uint32 reason, const BString& info) { if (state == fState) return; fState = state; + fStoppedReason = reason; + fStoppedReasonInfo = info; // unset CPU state and stack trace, if the thread isn't stopped if (fState != THREAD_STATE_STOPPED) { diff --git a/src/apps/debugger/model/Thread.h b/src/apps/debugger/model/Thread.h index f9a93f3981..94f2db7f21 100644 --- a/src/apps/debugger/model/Thread.h +++ b/src/apps/debugger/model/Thread.h @@ -17,12 +17,24 @@ class StackTrace; class Team; +// general thread state enum { THREAD_STATE_UNKNOWN, THREAD_STATE_RUNNING, THREAD_STATE_STOPPED }; +// reason why stopped +enum { + THREAD_STOPPED_UNKNOWN, + THREAD_STOPPED_DEBUGGED, + THREAD_STOPPED_DEBUGGER_CALL, + THREAD_STOPPED_BREAKPOINT, + THREAD_STOPPED_WATCHPOINT, + THREAD_STOPPED_SINGLE_STEP, + THREAD_STOPPED_EXCEPTION +}; + class Thread : public Referenceable, public DoublyLinkedListLinkImpl { public: @@ -40,7 +52,14 @@ public: void SetName(const BString& name); uint32 State() const { return fState; } - void SetState(uint32 state); + void SetState(uint32 state, + uint32 reason = THREAD_STOPPED_UNKNOWN, + const BString& info = BString()); + + uint32 StoppedReason() const + { return fStoppedReason; } + const BString& StoppedReasonInfo() const + { return fStoppedReasonInfo; } CpuState* GetCpuState() const { return fCpuState; } void SetCpuState(CpuState* state); @@ -53,6 +72,8 @@ private: thread_id fID; BString fName; uint32 fState; + uint32 fStoppedReason; + BString fStoppedReasonInfo; CpuState* fCpuState; StackTrace* fStackTrace; };