diff options
Diffstat (limited to 'src/plugins')
23 files changed, 294 insertions, 162 deletions
diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 02302016a7..37b81aab8c 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -1302,15 +1302,6 @@ void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, c updateLocals(); } -void CdbEngine::parseThreads(const GdbMi &data, int forceCurrentThreadId /* = -1 */) -{ - int currentThreadId; - Threads threads = ThreadsHandler::parseGdbmiThreads(data, ¤tThreadId); - threadsHandler()->setThreads(threads); - threadsHandler()->setCurrentThreadId(forceCurrentThreadId >= 0 ? - forceCurrentThreadId : currentThreadId); -} - void CdbEngine::handleThreads(const CdbExtensionCommandPtr &reply) { if (debug) @@ -1318,7 +1309,7 @@ void CdbEngine::handleThreads(const CdbExtensionCommandPtr &reply) if (reply->success) { GdbMi data; data.fromString(reply->reply); - parseThreads(data); + threadsHandler()->updateThreads(data); // Continue sequence postCommandSequence(reply->commandSequence); } else { @@ -1514,15 +1505,14 @@ void CdbEngine::updateLocals(bool forNewStackFrame) QVariant(flags)); } -void CdbEngine::selectThread(int index) +void CdbEngine::selectThread(ThreadId threadId) { - if (index < 0 || index == threadsHandler()->currentThread()) + if (!threadId.isValid() || threadId == threadsHandler()->currentThread()) return; - const int newThreadId = threadsHandler()->threads().at(index).id; - threadsHandler()->setCurrentThread(index); + threadsHandler()->setCurrentThread(threadId); - const QByteArray cmd = '~' + QByteArray::number(newThreadId) + " s"; + const QByteArray cmd = '~' + QByteArray::number(threadId.raw()) + " s"; postBuiltinCommand(cmd, 0, &CdbEngine::dummyHandler, CommandListStack); } @@ -2179,7 +2169,7 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT // Further examine stop and report to user QString message; QString exceptionBoxMessage; - int forcedThreadId = -1; + ThreadId forcedThreadId; const unsigned stopFlags = examineStopReason(stopReason, &message, &exceptionBoxMessage, conditionalBreakPointTriggered); // Do the non-blocking log reporting @@ -2216,7 +2206,7 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT if (stopFlags & StopInArtificialThread) { showMessage(tr("Switching to main thread..."), LogMisc); postCommand("~0 s", 0); - forcedThreadId = 0; + forcedThreadId = ThreadId(0); // Re-fetch stack again. postCommandSequence(CommandListStack); } else { @@ -2232,7 +2222,9 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT } const GdbMi threads = stopReason.findChild("threads"); if (threads.isValid()) { - parseThreads(threads, forcedThreadId); + threadsHandler()->updateThreads(threads); + if (forcedThreadId.isValid()) + threadsHandler()->setCurrentThread(forcedThreadId); } else { showMessage(QString::fromLatin1(stopReason.findChild("threaderror").data()), LogError); } @@ -2938,7 +2930,7 @@ void CdbEngine::postCommandSequence(unsigned mask) return; } if (mask & CommandListRegisters) { - QTC_ASSERT(threadsHandler()->currentThread() >= 0, return); + QTC_ASSERT(threadsHandler()->currentThreadIndex() >= 0, return); postExtensionCommand("registers", QByteArray(), 0, &CdbEngine::handleRegisters, mask & ~CommandListRegisters); return; } diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index 28fe96eaa6..b9a4eca4a9 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -32,6 +32,7 @@ #include "debuggerengine.h" #include "breakpoint.h" +#include "threaddata.h" #include <QSharedPointer> #include <QProcess> @@ -113,7 +114,7 @@ public: virtual void executeDebuggerCommand(const QString &command, DebuggerLanguages languages); virtual void activateFrame(int index); - virtual void selectThread(int index); + virtual void selectThread(ThreadId threadId); virtual bool stateAcceptsBreakpointChanges() const; virtual bool acceptsBreakpoint(BreakpointModelId id) const; @@ -242,7 +243,6 @@ private: int elapsedLogTime() const; void addLocalsOptions(ByteArrayInputStream &s) const; unsigned parseStackTrace(const GdbMi &data, bool sourceStepInto); - void parseThreads(const GdbMi &, int forceCurrentThreadId = -1); const QByteArray m_creatorExtPrefix; const QByteArray m_tokenPrefix; diff --git a/src/plugins/debugger/cdb/cdbparsehelpers.cpp b/src/plugins/debugger/cdb/cdbparsehelpers.cpp index 8842d5ce4a..ce54909b8d 100644 --- a/src/plugins/debugger/cdb/cdbparsehelpers.cpp +++ b/src/plugins/debugger/cdb/cdbparsehelpers.cpp @@ -263,7 +263,7 @@ static inline bool parseThread(QByteArray line, ThreadData *thread, bool *curren thread->targetId = QLatin1String("0x") + QString::fromLatin1(pidTid.mid(dotPos + 1)); } case 1: - thread->id = tokens.at(0).toInt(); + thread->id = ThreadId(tokens.at(0).toInt()); break; } // switch size return true; diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 790d8ee015..aa676f8544 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -1233,10 +1233,6 @@ void DebuggerEngine::setState(DebuggerState state, bool forced) handler->notifyBreakpointReleased(id); } - const bool running = d->m_state == InferiorRunOk; - if (running) - threadsHandler()->notifyRunning(); - showMessage(msg, LogDebug); updateViews(); @@ -1586,10 +1582,6 @@ void DebuggerEngine::changeBreakpoint(BreakpointModelId id) QTC_CHECK(false); } -void DebuggerEngine::selectThread(int) -{ -} - void DebuggerEngine::assignValueInDebugger(const WatchData *, const QString &, const QVariant &) { diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index e5019db333..8fedcf0f75 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -32,7 +32,8 @@ #include "debugger_global.h" #include "debuggerconstants.h" -#include "breakpoint.h" // For 'BreakpointId' +#include "breakpoint.h" // For BreakpointModelId. +#include "threaddata.h" // For ThreadId. #include <QObject> #include <QStringList> @@ -205,7 +206,7 @@ public: virtual bool acceptsDebuggerCommands() const { return true; } virtual void assignValueInDebugger(const Internal::WatchData *data, const QString &expr, const QVariant &value); - virtual void selectThread(int index); + virtual void selectThread(Internal::ThreadId threadId) = 0; virtual Internal::ModulesHandler *modulesHandler() const; virtual Internal::RegisterHandler *registerHandler() const; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index ea79ab1220..0b30d33838 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -494,6 +494,7 @@ public: bool hasCapability(unsigned cap) const; bool acceptsBreakpoint(BreakpointModelId) const { return false; } bool acceptsDebuggerCommands() const { return false; } + void selectThread(ThreadId) {} }; bool DummyEngine::hasCapability(unsigned cap) const @@ -781,7 +782,8 @@ public slots: void selectThread(int index) { - currentEngine()->selectThread(index); + ThreadId id = m_currentEngine->threadsHandler()->threadAt(index); + m_currentEngine->selectThread(id); } void breakpointSetMarginActionTriggered() @@ -2205,7 +2207,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) QTC_ASSERT(m_returnWindow->model(), return); QTC_ASSERT(!engine->isSlaveEngine(), return); - m_threadBox->setCurrentIndex(engine->threadsHandler()->currentThread()); + m_threadBox->setCurrentIndex(engine->threadsHandler()->currentThreadIndex()); engine->watchHandler()->updateWatchersWindow(); const DebuggerState state = engine->state(); diff --git a/src/plugins/debugger/debuggerstreamops.cpp b/src/plugins/debugger/debuggerstreamops.cpp index ae178ccab4..c7ec18b054 100644 --- a/src/plugins/debugger/debuggerstreamops.cpp +++ b/src/plugins/debugger/debuggerstreamops.cpp @@ -40,7 +40,7 @@ namespace Internal { QDataStream &operator<<(QDataStream &stream, const ThreadData &d) { - stream << (qint64)d.id; + stream << d.id.raw(); stream << d.address; stream << d.function; stream << d.fileName; @@ -54,7 +54,7 @@ QDataStream &operator>>(QDataStream &stream, ThreadData &d) { qint64 id; stream >> id; - d.id = id; + d.id = ThreadId(id); stream >> d.address; stream >> d.function; stream >> d.fileName; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index a93c154e85..6f6da49de3 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -467,6 +467,8 @@ void GdbEngine::handleResponse(const QByteArray &buff) m_pendingLogStreamOutput.clear(); m_pendingConsoleStreamOutput.clear(); } else if (asyncClass == "running") { + GdbMi threads = result.findChild("thread-id"); + threadsHandler()->notifyRunning(threads.data()); if (state() == InferiorRunOk || state() == InferiorSetupRequested) { // We get multiple *running after thread creation and in Windows terminals. showMessage(QString::fromLatin1("NOTE: INFERIOR STILL RUNNING IN STATE %1."). @@ -527,6 +529,10 @@ void GdbEngine::handleResponse(const QByteArray &buff) //"{id="1",group-id="28902"}" QByteArray id = result.findChild("id").data(); showStatusMessage(tr("Thread %1 created").arg(_(id)), 1000); + ThreadData thread; + thread.id = ThreadId(id.toLong()); + thread.groupId = result.findChild("group-id").data(); + threadsHandler()->updateThread(thread); } else if (asyncClass == "thread-group-exited") { // Archer has "{id="28902"}" QByteArray id = result.findChild("id").data(); @@ -538,6 +544,7 @@ void GdbEngine::handleResponse(const QByteArray &buff) QByteArray groupid = result.findChild("group-id").data(); showStatusMessage(tr("Thread %1 in group %2 exited") .arg(_(id)).arg(_(groupid)), 1000); + threadsHandler()->removeThread(ThreadId(id.toLong())); } else if (asyncClass == "thread-selected") { QByteArray id = result.findChild("id").data(); showStatusMessage(tr("Thread %1 selected").arg(_(id)), 1000); @@ -1397,6 +1404,9 @@ void GdbEngine::handleStopResponse(const GdbMi &data) return; } + GdbMi threads = data.findChild("stopped-thread"); + threadsHandler()->notifyStopped(threads.data()); + const QByteArray reason = data.findChild("reason").data(); if (isExitedReason(reason)) { @@ -1748,10 +1758,6 @@ void GdbEngine::handleStop2(const GdbMi &data) // Let the event loop run before deciding whether to update the stack. m_stackNeeded = true; // setTokenBarrier() might reset this. - if (isStopperThread) - m_currentThreadId = 0; - else - m_currentThreadId = data.findChild("thread-id").data().toInt(); QTimer::singleShot(0, this, SLOT(handleStop2())); } @@ -3489,15 +3495,12 @@ void GdbEngine::reloadSourceFilesInternal() // ////////////////////////////////////////////////////////////////////// -void GdbEngine::selectThread(int index) +void GdbEngine::selectThread(ThreadId threadId) { - threadsHandler()->setCurrentThread(index); - Threads threads = threadsHandler()->threads(); - QTC_ASSERT(index < threads.size(), return); - const int id = threads.at(index).id; + threadsHandler()->setCurrentThread(threadId); showStatusMessage(tr("Retrieving data for stack view thread 0x%1...") - .arg(id, 0, 16), 10000); - postCommand("-thread-select " + QByteArray::number(id), Discardable, + .arg(threadId.raw(), 0, 16), 10000); + postCommand("-thread-select " + QByteArray::number(threadId.raw()), Discardable, CB(handleStackSelectThread)); } @@ -3641,11 +3644,7 @@ void GdbEngine::handleStackSelectFrame(const GdbResponse &response) void GdbEngine::handleThreadInfo(const GdbResponse &response) { if (response.resultClass == GdbResultDone) { - int currentThreadId; - const Threads threads = - ThreadsHandler::parseGdbmiThreads(response.data, ¤tThreadId); - threadsHandler()->setThreads(threads); - threadsHandler()->setCurrentThreadId(currentThreadId); + threadsHandler()->updateThreads(response.data); updateViews(); // Adjust Threads combobox. if (m_hasInferiorThreadList && debuggerCore()->boolSetting(ShowThreadNames)) { postCommand("threadnames " + @@ -3663,37 +3662,28 @@ void GdbEngine::handleThreadListIds(const GdbResponse &response) { // "72^done,{thread-ids={thread-id="2",thread-id="1"},number-of-threads="2"} // In gdb 7.1+ additionally: current-thread-id="1" + ThreadsHandler *handler = threadsHandler(); const QList<GdbMi> items = response.data.findChild("thread-ids").children(); - Threads threads; for (int index = 0, n = items.size(); index != n; ++index) { ThreadData thread; - thread.id = items.at(index).data().toInt(); - threads.append(thread); + thread.id = ThreadId(items.at(index).data().toInt()); + handler->updateThread(thread); } - threadsHandler()->setThreads(threads); - threadsHandler()->setCurrentThreadId(m_currentThreadId); } void GdbEngine::handleThreadNames(const GdbResponse &response) { if (response.resultClass == GdbResultDone) { + ThreadsHandler *handler = threadsHandler(); GdbMi names; names.fromString(response.consoleStreamOutput); - - Threads threads = threadsHandler()->threads(); - foreach (const GdbMi &name, names.children()) { - int id = name.findChild("id").data().toInt(); - for (int index = 0, n = threads.size(); index != n; ++index) { - ThreadData &thread = threads[index]; - if (thread.id == quint64(id)) { - thread.name = decodeData(name.findChild("value").data(), - name.findChild("valueencoded").data().toInt()); - break; - } - } + ThreadData thread; + thread.id = ThreadId(name.findChild("id").data().toInt()); + thread.name = decodeData(name.findChild("value").data(), + name.findChild("valueencoded").data().toInt()); + handler->updateThread(thread); } - threadsHandler()->setThreads(threads); updateViews(); } } diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index ed8f2f9cc3..8ad5846920 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -35,6 +35,7 @@ #include "stackframe.h" #include "watchhandler.h" #include "watchutils.h" +#include "threaddata.h" #include <QByteArray> #include <QProcess> @@ -437,7 +438,7 @@ private: ////////// Inferior Management ////////// private: ////////// View & Data Stuff ////////// protected: - void selectThread(int index); + void selectThread(ThreadId threadId); void activateFrame(int index); void resetLocation(); @@ -664,7 +665,6 @@ protected: // For short-circuiting stack and thread list evaluation. bool m_stackNeeded; - int m_currentThreadId; // // Qml diff --git a/src/plugins/debugger/lldb/ipcenginehost.cpp b/src/plugins/debugger/lldb/ipcenginehost.cpp index 8145fa6391..84ac83e0cc 100644 --- a/src/plugins/debugger/lldb/ipcenginehost.cpp +++ b/src/plugins/debugger/lldb/ipcenginehost.cpp @@ -208,7 +208,6 @@ void IPCEngineHost::executeJumpToLine(const ContextData &data) rpcCall(ExecuteJumpToLine, p); } - void IPCEngineHost::activateFrame(int index) { resetLocation(); @@ -221,16 +220,15 @@ void IPCEngineHost::activateFrame(int index) rpcCall(ActivateFrame, p); } -void IPCEngineHost::selectThread(int index) +void IPCEngineHost::selectThread(ThreadId id) { resetLocation(); - Threads threads = threadsHandler()->threads(); - QTC_ASSERT(index < threads.size(), return); + QTC_ASSERT(id.isValid(), return); QByteArray p; { QDataStream s(&p, QIODevice::WriteOnly); SET_NATIVE_BYTE_ORDER(s); - s << quint64(threads.at(index).id); + s << id.raw(); } rpcCall(SelectThread, p); } @@ -442,7 +440,7 @@ void IPCEngineHost::rpcCallback(quint64 f, QByteArray payload) SET_NATIVE_BYTE_ORDER(s); quint64 token; s >> token; - threadsHandler()->setCurrentThreadId(token); + threadsHandler()->setCurrentThread(ThreadId(token)); } break; case IPCEngineGuest::ListFrames: diff --git a/src/plugins/debugger/lldb/ipcenginehost.h b/src/plugins/debugger/lldb/ipcenginehost.h index c70672bc31..fd89ee4458 100644 --- a/src/plugins/debugger/lldb/ipcenginehost.h +++ b/src/plugins/debugger/lldb/ipcenginehost.h @@ -104,7 +104,7 @@ public: void executeRunToFunction(const QString &functionName); void executeJumpToLine(const ContextData &data); void activateFrame(int index); - void selectThread(int index); + void selectThread(ThreadId index); void fetchDisassembler(DisassemblerAgent *); bool acceptsBreakpoint(BreakpointModelId) const { return true; } // FIXME void insertBreakpoint(BreakpointModelId id); diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 551f712bd6..8539d99048 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -321,9 +321,9 @@ void PdbEngine::activateFrame(int frameIndex) gotoLocation(handler->currentFrame()); } -void PdbEngine::selectThread(int index) +void PdbEngine::selectThread(ThreadId threadId) { - Q_UNUSED(index) + Q_UNUSED(threadId) } bool PdbEngine::acceptsBreakpoint(BreakpointModelId id) const diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h index 6c8365a0a3..82cdd81ac7 100644 --- a/src/plugins/debugger/pdb/pdbengine.h +++ b/src/plugins/debugger/pdb/pdbengine.h @@ -86,7 +86,7 @@ private: void executeJumpToLine(const ContextData &data); void activateFrame(int index); - void selectThread(int index); + void selectThread(ThreadId threadId); bool acceptsBreakpoint(BreakpointModelId id) const; void insertBreakpoint(BreakpointModelId id); diff --git a/src/plugins/debugger/qml/qmlcppengine.cpp b/src/plugins/debugger/qml/qmlcppengine.cpp index 7018c7a45c..f1e789d55c 100644 --- a/src/plugins/debugger/qml/qmlcppengine.cpp +++ b/src/plugins/debugger/qml/qmlcppengine.cpp @@ -267,9 +267,9 @@ bool QmlCppEngine::acceptsBreakpoint(BreakpointModelId id) const || d->m_qmlEngine->acceptsBreakpoint(id); } -void QmlCppEngine::selectThread(int index) +void QmlCppEngine::selectThread(ThreadId threadId) { - d->m_activeEngine->selectThread(index); + d->m_activeEngine->selectThread(threadId); } void QmlCppEngine::assignValueInDebugger(const WatchData *data, diff --git a/src/plugins/debugger/qml/qmlcppengine.h b/src/plugins/debugger/qml/qmlcppengine.h index 052c777ff5..64f531277d 100644 --- a/src/plugins/debugger/qml/qmlcppengine.h +++ b/src/plugins/debugger/qml/qmlcppengine.h @@ -77,7 +77,7 @@ public: void attemptBreakpointSynchronization(); bool acceptsBreakpoint(BreakpointModelId id) const; - void selectThread(int index); + void selectThread(ThreadId threadId); void assignValueInDebugger(const WatchData *data, const QString &expr, const QVariant &value); diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index d1c22ef1c7..d16c71c2a7 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -778,9 +778,9 @@ void QmlEngine::activateFrame(int index) gotoLocation(stackHandler()->frames().value(index)); } -void QmlEngine::selectThread(int index) +void QmlEngine::selectThread(ThreadId threadId) { - Q_UNUSED(index) + Q_UNUSED(threadId) } void QmlEngine::insertBreakpoint(BreakpointModelId id) diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index e3f38708b9..7f51540333 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -139,7 +139,7 @@ private: void executeJumpToLine(const ContextData &data); void activateFrame(int index); - void selectThread(int index); + void selectThread(ThreadId threadId); void attemptBreakpointSynchronization(); void removeBreakpoint(BreakpointModelId id); diff --git a/src/plugins/debugger/script/scriptengine.cpp b/src/plugins/debugger/script/scriptengine.cpp index f13542ed95..5ea054604d 100644 --- a/src/plugins/debugger/script/scriptengine.cpp +++ b/src/plugins/debugger/script/scriptengine.cpp @@ -438,9 +438,9 @@ void ScriptEngine::activateFrame(int index) Q_UNUSED(index) } -void ScriptEngine::selectThread(int index) +void ScriptEngine::selectThread(ThreadId threadId) { - Q_UNUSED(index) + Q_UNUSED(threadId) } bool ScriptEngine::acceptsBreakpoint(BreakpointModelId id) const diff --git a/src/plugins/debugger/script/scriptengine.h b/src/plugins/debugger/script/scriptengine.h index 669ef21abb..72a912db14 100644 --- a/src/plugins/debugger/script/scriptengine.h +++ b/src/plugins/debugger/script/scriptengine.h @@ -85,7 +85,7 @@ private: void executeJumpToLine(const ContextData &data); void activateFrame(int index); - void selectThread(int index); + void selectThread(ThreadId threadId); bool acceptsBreakpoint(BreakpointModelId id) const; void attemptBreakpointSynchronization(); diff --git a/src/plugins/debugger/threaddata.h b/src/plugins/debugger/threaddata.h index bb2a2111e5..516ad9ab73 100644 --- a/src/plugins/debugger/threaddata.h +++ b/src/plugins/debugger/threaddata.h @@ -30,24 +30,49 @@ #ifndef THREADDATA_H #define THREADDATA_H -#include <QVector> #include <QString> +#include <QVector> namespace Debugger { namespace Internal { //////////////////////////////////////////////////////////////////////// // +// ThreadId +// +//////////////////////////////////////////////////////////////////////// + +/*! A typesafe identifier. */ +class ThreadId +{ +public: + ThreadId() : m_id(-1) {} + explicit ThreadId(qint64 id) : m_id(id) {} + + bool isValid() const { return m_id != -1; } + qint64 raw() const { return m_id; } + bool operator==(const ThreadId other) const { return m_id == other.m_id; } + +private: + qint64 m_id; +}; + +//////////////////////////////////////////////////////////////////////// +// // ThreadData // //////////////////////////////////////////////////////////////////////// -/*! A structure containing information about a single thread */ +/*! A structure containing information about a single thread. */ struct ThreadData { - ThreadData(quint64 threadid = 0) - : id(threadid), frameLevel(-1), address (0), lineNumber(-1) - {} + ThreadData() + { + frameLevel = -1; + lineNumber = -1; + address = 0; + stopped = true; + } enum { IdColumn, @@ -61,7 +86,9 @@ struct ThreadData DetailsColumn, CoreColumn, ComboNameColumn, - ColumnCount = CoreColumn + ColumnCount = CoreColumn, + + IdRole = Qt::UserRole }; void notifyRunning() // Clear state information. @@ -72,22 +99,25 @@ struct ThreadData frameLevel = -1; state.clear(); lineNumber = -1; + stopped = false; } // Permanent data. - quint64 id; + ThreadId id; + QByteArray groupId; QString targetId; QString core; + bool stopped; // State information when stopped. qint32 frameLevel; + qint32 lineNumber; quint64 address; QString function; QString module; QString fileName; QString details; QString state; - qint32 lineNumber; QString name; }; diff --git a/src/plugins/debugger/threadshandler.cpp b/src/plugins/debugger/threadshandler.cpp index b62627d570..d131f5ea86 100644 --- a/src/plugins/debugger/threadshandler.cpp +++ b/src/plugins/debugger/threadshandler.cpp @@ -34,6 +34,8 @@ #include "debuggerconstants.h" #include "debuggercore.h" +#include <utils/qtcassert.h> + #include <QDebug> #include <QTextStream> #include <QSortFilterProxyModel> @@ -41,6 +43,32 @@ namespace Debugger { namespace Internal { +void mergeThreadData(ThreadData &data, const ThreadData &other) +{ + if (!other.core.isEmpty()) + data.core = other.core; + if (!other.fileName.isEmpty()) + data.fileName = other.fileName; + if (!other.targetId.isEmpty()) + data.targetId = other.targetId; + if (!other.name.isEmpty()) + data.name = other.name; + if (other.frameLevel != -1) + data.frameLevel = other.frameLevel; + if (!other.function.isEmpty()) + data.function = other.function; + if (!other.address) + data.address = other.address; + if (!other.module.isEmpty()) + data.module = other.module; + if (!other.details.isEmpty()) + data.details = other.details; + if (!other.state.isEmpty()) + data.state = other.state; + if (other.lineNumber != -1) + data.lineNumber = other.lineNumber; +} + //////////////////////////////////////////////////////////////////////// // // ThreadsHandler @@ -56,10 +84,13 @@ static QString threadToolTip(const ThreadData &thread) QTextStream str(&rc); str << "<html><head/><body><table>" << start << ThreadsHandler::tr("Thread id:") - << sep << thread.id << end; + << sep << thread.id.raw() << end; if (!thread.targetId.isEmpty()) str << start << ThreadsHandler::tr("Target id:") << sep << thread.targetId << end; + if (!thread.groupId.isEmpty()) + str << start << ThreadsHandler::tr("Group id:") + << sep << thread.groupId << end; if (!thread.name.isEmpty()) str << start << ThreadsHandler::tr("Name:") << sep << thread.name << end; @@ -98,14 +129,13 @@ static QString threadToolTip(const ThreadData &thread) */ ThreadsHandler::ThreadsHandler() - : m_currentIndex(0), + : m_currentIndex(-1), m_positionIcon(QLatin1String(":/debugger/images/location_16.png")), m_emptyIcon(QLatin1String(":/debugger/images/debugger_empty_14.png")) { m_resetLocationScheduled = false; - m_contentsValid = false; - m_proxyModel = new QSortFilterProxyModel(this); - m_proxyModel->setSourceModel(this); +// m_proxyModel = new QSortFilterProxyModel(this); +// m_proxyModel->setSourceModel(this); } int ThreadsHandler::rowCount(const QModelIndex &parent) const @@ -132,7 +162,7 @@ QVariant ThreadsHandler::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case ThreadData::IdColumn: - return thread.id; + return thread.id.raw(); case ThreadData::FunctionColumn: return thread.function; case ThreadData::FileColumn: @@ -157,7 +187,7 @@ QVariant ThreadsHandler::data(const QModelIndex &index, int role) const case ThreadData::DetailsColumn: return thread.details; case ThreadData::ComboNameColumn: - return QString::fromLatin1("#%1 %2").arg(thread.id).arg(thread.name); + return QString::fromLatin1("#%1 %2").arg(thread.id.raw()).arg(thread.name); } case Qt::ToolTipRole: return threadToolTip(thread); @@ -166,6 +196,8 @@ QVariant ThreadsHandler::data(const QModelIndex &index, int role) const if (index.column() == 0) return (index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon; break; + case ThreadData::IdRole: + return thread.id.raw(); default: break; } @@ -204,52 +236,79 @@ QVariant ThreadsHandler::headerData Qt::ItemFlags ThreadsHandler::flags(const QModelIndex &index) const { - return m_contentsValid ? QAbstractTableModel::flags(index) : Qt::ItemFlags(0); + const int row = index.row(); + const bool stopped = row >= 0 && row < m_threads.size() + && m_threads.at(row).stopped; + return stopped ? QAbstractTableModel::flags(index) : Qt::ItemFlags(0); } -int ThreadsHandler::currentThreadId() const +ThreadId ThreadsHandler::currentThread() const { if (m_currentIndex < 0 || m_currentIndex >= m_threads.size()) - return -1; + return ThreadId(); return m_threads[m_currentIndex].id; } -void ThreadsHandler::setCurrentThread(int index) +ThreadId ThreadsHandler::threadAt(int index) const { + QTC_ASSERT(index >= 0 && index < m_threads.size(), return ThreadId()); + return m_threads[index].id; +} + +void ThreadsHandler::setCurrentThread(ThreadId id) +{ + const int index = indexOf(id); if (index == m_currentIndex) return; + if (index == -1) { + qWarning("ThreadsHandler::setCurrentThreadId: No such thread %d.", int(id.raw())); + return; + } + // Emit changed for previous frame. - QModelIndex i = ThreadsHandler::index(m_currentIndex, 0); - emit dataChanged(i, i); + if (m_currentIndex != -1) + dataChanged(m_currentIndex); m_currentIndex = index; // Emit changed for new frame. - i = ThreadsHandler::index(m_currentIndex, 0); - emit dataChanged(i, i); + dataChanged(m_currentIndex); updateThreadBox(); } -void ThreadsHandler::setCurrentThreadId(int id) -{ - const int index = indexOf(id); - if (index != -1) - setCurrentThread(index); - else - qWarning("ThreadsHandler::setCurrentThreadId: No such thread %d.", id); -} - -int ThreadsHandler::indexOf(quint64 threadId) const +int ThreadsHandler::indexOf(ThreadId threadId) const { - const int count = m_threads.size(); - for (int i = 0; i < count; ++i) + for (int i = m_threads.size(); --i >= 0; ) if (m_threads.at(i).id == threadId) return i; return -1; } +void ThreadsHandler::updateThread(const ThreadData &thread) +{ + const int i = indexOf(thread.id); + if (i == -1) { + beginInsertRows(QModelIndex(), m_threads.size(), m_threads.size()); + m_threads.append(thread); + endInsertRows(); + } else { + mergeThreadData(m_threads[i], thread); + dataChanged(i); + } +} + +void ThreadsHandler::removeThread(ThreadId threadId) +{ + const int i = indexOf(threadId); + if (i == -1) + return; + beginRemoveRows(QModelIndex(), i, i); + m_threads.remove(i); + endRemoveRows(); +} + void ThreadsHandler::setThreads(const Threads &threads) { beginResetModel(); @@ -257,7 +316,6 @@ void ThreadsHandler::setThreads(const Threads &threads) if (m_currentIndex >= m_threads.size()) m_currentIndex = -1; m_resetLocationScheduled = false; - m_contentsValid = true; endResetModel(); updateThreadBox(); } @@ -266,38 +324,96 @@ void ThreadsHandler::updateThreadBox() { QStringList list; foreach (const ThreadData &thread, m_threads) - list.append(QString::fromLatin1("#%1 %2").arg(thread.id).arg(thread.name)); + list.append(QString::fromLatin1("#%1 %2").arg(thread.id.raw()).arg(thread.name)); debuggerCore()->setThreads(list, m_currentIndex); } +void ThreadsHandler::dataChanged(int index) +{ + Q_UNUSED(index); + layoutChanged(); +} + Threads ThreadsHandler::threads() const { return m_threads; } +ThreadData ThreadsHandler::thread(ThreadId id) const +{ + const int i = indexOf(id); + return i == -1 ? ThreadData() : m_threads.at(i); +} + void ThreadsHandler::removeAll() { beginResetModel(); m_threads.clear(); - m_currentIndex = 0; + m_currentIndex = -1; endResetModel(); } -void ThreadsHandler::notifyRunning() +void ThreadsHandler::notifyRunning(const QByteArray &data) { - // Threads stopped (that is, address != 0 showing)? - if (m_threads.empty()) - return; - if (m_threads.front().address == 0) - return; - const Threads::iterator end = m_threads.end(); - for (Threads::iterator it = m_threads.begin(); it != end; ++it) - it->notifyRunning(); - emit dataChanged(index(0, 1), - index(m_threads.size() - 1, ThreadData::ColumnCount - 1)); + if (data.isEmpty() || data == "all") { + notifyAllRunning(); + } else { + bool ok; + qlonglong id = data.toLongLong(&ok); + if (ok) + notifyRunning(ThreadId(id)); + else // FIXME + notifyAllRunning(); + } +} + +void ThreadsHandler::notifyAllRunning() +{ + for (int i = m_threads.size(); --i >= 0; ) + m_threads[i].notifyRunning(); + layoutChanged(); +} + +void ThreadsHandler::notifyRunning(ThreadId id) +{ + int i = indexOf(id); + if (i >= 0) { + m_threads[i].notifyRunning(); + dataChanged(i); + } } -Threads ThreadsHandler::parseGdbmiThreads(const GdbMi &data, int *currentThread) +void ThreadsHandler::notifyStopped(const QByteArray &data) +{ + if (data.isEmpty() || data == "all") { + notifyAllStopped(); + } else { + bool ok; + qlonglong id = data.toLongLong(&ok); + if (ok) + notifyRunning(ThreadId(id)); + else // FIXME + notifyAllStopped(); + } +} + +void ThreadsHandler::notifyAllStopped() +{ + for (int i = m_threads.size(); --i >= 0; ) + m_threads[i].stopped = true; + layoutChanged(); +} + +void ThreadsHandler::notifyStopped(ThreadId id) +{ + int i = indexOf(id); + if (i >= 0) { + m_threads[i].stopped = true; + dataChanged(i); + } +} + +void ThreadsHandler::updateThreads(const GdbMi &data) { // ^done,threads=[{id="1",target-id="Thread 0xb7fdc710 (LWP 4264)", // frame={level="0",addr="0x080530bf",func="testQString",args=[], @@ -305,14 +421,12 @@ Threads ThreadsHandler::parseGdbmiThreads(const GdbMi &data, int *currentThread) // state="stopped",core="0"}],current-thread-id="1" const QList<GdbMi> items = data.findChild("threads").children(); const int n = items.size(); - Threads threads; - threads.reserve(n); for (int index = 0; index != n; ++index) { bool ok = false; const GdbMi item = items.at(index); const GdbMi frame = item.findChild("frame"); ThreadData thread; - thread.id = item.findChild("id").data().toInt(); + thread.id = ThreadId(item.findChild("id").data().toInt()); thread.targetId = QString::fromLatin1(item.findChild("target-id").data()); thread.details = QString::fromLatin1(item.findChild("details").data()); thread.core = QString::fromLatin1(item.findChild("core").data()); @@ -322,33 +436,36 @@ Threads ThreadsHandler::parseGdbmiThreads(const GdbMi &data, int *currentThread) thread.fileName = QString::fromLatin1(frame.findChild("fullname").data()); thread.lineNumber = frame.findChild("line").data().toInt(); thread.module = QString::fromLocal8Bit(frame.findChild("from").data()); + thread.stopped = true; // Non-GDB (Cdb2) output name here. thread.name = QString::fromLatin1(frame.findChild("name").data()); - threads.append(thread); + if (thread.state == QLatin1String("running")) + thread.stopped = false; + updateThread(thread); } - if (currentThread) - *currentThread = data.findChild("current-thread-id").data().toInt(); - return threads; + const GdbMi current = data.findChild("current-thread-id"); + if (current.isValid()) + setCurrentThread(ThreadId(current.data().toLongLong())); + updateThreadBox(); } void ThreadsHandler::scheduleResetLocation() { m_resetLocationScheduled = true; - m_contentsValid = false; } void ThreadsHandler::resetLocation() { if (m_resetLocationScheduled) { - beginResetModel(); m_resetLocationScheduled = false; - endResetModel(); + layoutChanged(); } } QAbstractItemModel *ThreadsHandler::model() { - return m_proxyModel; + return this; + //return m_proxyModel; } } // namespace Internal diff --git a/src/plugins/debugger/threadshandler.h b/src/plugins/debugger/threadshandler.h index 30d3fbdd46..3949c86c2c 100644 --- a/src/plugins/debugger/threadshandler.h +++ b/src/plugins/debugger/threadshandler.h @@ -57,26 +57,35 @@ class ThreadsHandler : public QAbstractTableModel public: ThreadsHandler(); - int currentThread() const { return m_currentIndex; } - void setCurrentThread(int index); - int currentThreadId() const; - void setCurrentThreadId(int id); - int indexOf(quint64 threadId) const; + int currentThreadIndex() const { return m_currentIndex; } + ThreadId currentThread() const; + ThreadId threadAt(int index) const; + void setCurrentThread(ThreadId id); + void updateThread(const ThreadData &thread); + void updateThreads(const GdbMi &data); + + void removeThread(ThreadId threadId); void setThreads(const Threads &threads); void removeAll(); Threads threads() const; + ThreadData thread(ThreadId id) const; QAbstractItemModel *model(); // Clear out all frame information - void notifyRunning(); + void notifyRunning(const QByteArray &data); + void notifyRunning(ThreadId id); + void notifyAllRunning(); - static Threads parseGdbmiThreads(const GdbMi &data, int *currentThread = 0); + void notifyStopped(const QByteArray &data); + void notifyStopped(ThreadId id); + void notifyAllStopped(); void resetLocation(); void scheduleResetLocation(); private: + int indexOf(ThreadId threadId) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; @@ -84,6 +93,7 @@ private: int role = Qt::DisplayRole) const; Qt::ItemFlags flags(const QModelIndex &index) const; void updateThreadBox(); + void dataChanged(int index); Threads m_threads; int m_currentIndex; @@ -91,9 +101,8 @@ private: const QIcon m_emptyIcon; bool m_resetLocationScheduled; - bool m_contentsValid; - QSortFilterProxyModel *m_proxyModel; + //QSortFilterProxyModel *m_proxyModel; }; } // namespace Internal diff --git a/src/plugins/debugger/threadswindow.cpp b/src/plugins/debugger/threadswindow.cpp index a52228ac56..2a764c4031 100644 --- a/src/plugins/debugger/threadswindow.cpp +++ b/src/plugins/debugger/threadswindow.cpp @@ -53,7 +53,8 @@ ThreadsTreeView::ThreadsTreeView() void ThreadsTreeView::rowActivated(const QModelIndex &index) { - debuggerCore()->currentEngine()->selectThread(index.row()); + ThreadId id = ThreadId(index.data(ThreadData::IdRole).toLongLong()); + debuggerCore()->currentEngine()->selectThread(id); } void ThreadsTreeView::setModel(QAbstractItemModel *model) |