From efb02a30a0315dc921b823453a99b74e8b9c8ff7 Mon Sep 17 00:00:00 2001 From: hjk <qtc-committer@nokia.com> Date: Mon, 21 Sep 2009 17:35:19 +0200 Subject: [PATCH] debugger: rework plain gdb shutdown logic --- src/plugins/debugger/gdb/abstractgdbadapter.h | 28 +++++- src/plugins/debugger/gdb/gdbengine.cpp | 60 ++++++------- src/plugins/debugger/gdb/gdbengine.h | 5 ++ src/plugins/debugger/gdb/plaingdbadapter.cpp | 86 +++++++++++++++---- src/plugins/debugger/gdb/plaingdbadapter.h | 5 +- src/plugins/debugger/gdb/trkgdbadapter.cpp | 5 +- src/plugins/debugger/gdb/trkgdbadapter.h | 2 +- 7 files changed, 140 insertions(+), 51 deletions(-) diff --git a/src/plugins/debugger/gdb/abstractgdbadapter.h b/src/plugins/debugger/gdb/abstractgdbadapter.h index d8dd46e101c..9b30ab9fd3c 100644 --- a/src/plugins/debugger/gdb/abstractgdbadapter.h +++ b/src/plugins/debugger/gdb/abstractgdbadapter.h @@ -40,6 +40,26 @@ namespace Internal { class GdbEngine; +enum GdbAdapterState +{ + AdapterNotRunning, + AdapterStarting, + AdapterStarted, + AdapterStartFailed, + InferiorPreparing, + InferiorPrepared, + InferiorPreparationFailed, + InferiorStarting, + InferiorStarted, + InferiorStartFailed, + InferiorShuttingDown, + InferiorShutDown, + InferiorShutdownFailed, + AdapterShuttingDown, + //AdapterShutDown, // use AdapterNotRunning + AdapterShutdownFailed, +}; + // AbstractGdbAdapter is inherited by PlainGdbAdapter used for local // debugging and TrkGdbAdapter used for on-device debugging. // In the PlainGdbAdapter case it's just a wrapper around a QProcess running @@ -51,10 +71,9 @@ class AbstractGdbAdapter : public QObject public: AbstractGdbAdapter(GdbEngine *engine, QObject *parent = 0) - : QObject(parent), m_engine(engine) + : QObject(parent), m_engine(engine), m_state(AdapterNotRunning) {} - virtual QProcess::ProcessState state() const = 0; virtual QString errorString() const = 0; virtual QByteArray readAllStandardError() = 0; virtual QByteArray readAllStandardOutput() = 0; @@ -90,8 +109,13 @@ signals: void readyReadStandardOutput(); void readyReadStandardError(); +public: + virtual GdbAdapterState state() const { return m_state; } protected: + virtual void setState(GdbAdapterState state) { m_state = state; } + GdbEngine * const m_engine; + GdbAdapterState m_state; }; } // namespace Internal diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index aa72c981749..7985e28417c 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -661,10 +661,10 @@ void GdbEngine::readGdbStandardOutput() void GdbEngine::interruptInferior() { - debugMessage(_("GDBENGINE INTERRUPT INFERIOR: %1").arg(m_gdbAdapter->state())); +// debugMessage(_("GDBENGINE INTERRUPT INFERIOR: %1").arg(m_gdbAdapter->state())); qq->notifyInferiorStopRequested(); - if (m_gdbAdapter->state() == QProcess::NotRunning) { + if (m_gdbAdapter->state() == AdapterNotRunning) { debugMessage(_("TRYING TO INTERRUPT INFERIOR WITHOUT RUNNING GDB")); qq->notifyInferiorExited(); return; @@ -691,6 +691,13 @@ void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0) void GdbEngine::postCommand(const QString &command, AdapterCallback callback, const char *callbackName, const QVariant &cookie) +{ + postCommand(command, NoFlags, callback, callbackName, cookie); +} + +void GdbEngine::postCommand(const QString &command, GdbCommandFlags flags, + AdapterCallback callback, + const char *callbackName, const QVariant &cookie) { GdbCommand cmd; cmd.command = command; @@ -722,7 +729,7 @@ void GdbEngine::postCommand(const QString &command, GdbCommandFlags flags, void GdbEngine::postCommandHelper(const GdbCommand &cmd) { - if (m_gdbAdapter->state() == QProcess::NotRunning) { + if (m_gdbAdapter->state() == AdapterNotRunning) { debugMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: ") + cmd.command); return; } @@ -753,7 +760,7 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd) void GdbEngine::flushCommand(const GdbCommand &cmd0) { GdbCommand cmd = cmd0; - if (m_gdbAdapter->state() != QProcess::Running) { + if (m_gdbAdapter->state() == AdapterNotRunning) { emit gdbInputAvailable(LogInput, cmd.command); debugMessage(_("GDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + cmd.command); return; @@ -858,7 +865,7 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record) void GdbEngine::executeDebuggerCommand(const QString &command) { - if (m_gdbAdapter->state() != QProcess::Running) { + if (m_gdbAdapter->state() == AdapterNotRunning) { debugMessage(_("GDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command); return; } @@ -1484,7 +1491,9 @@ QString GdbEngine::fullName(const QStringList &candidates) void GdbEngine::shutdown() { - exitDebugger(); + m_outputCollector.shutdown(); + initializeVariables(); + m_gdbAdapter->shutdownAdapter(); } void GdbEngine::detachDebugger() @@ -1496,29 +1505,9 @@ void GdbEngine::detachDebugger() void GdbEngine::exitDebugger() { - debugMessage(_("GDBENGINE EXITDEBUGGER: %1").arg(m_gdbAdapter->state())); - if (m_gdbAdapter->state() == QProcess::Starting) { - debugMessage(_("WAITING FOR GDB STARTUP TO SHUTDOWN: %1") - .arg(m_gdbAdapter->state())); - // FIXME: handle this! - //m_gdbAdapter->waitForStarted(); - } - if (m_gdbAdapter->state() == QProcess::Running) { - debugMessage(_("WAITING FOR RUNNING GDB TO SHUTDOWN: %1") - .arg(m_gdbAdapter->state())); - if (status() != DebuggerInferiorStopped - && status() != DebuggerProcessStartingUp) { - QTC_ASSERT(status() == DebuggerInferiorRunning, - qDebug() << "STATUS ON EXITDEBUGGER:" << status()); - interruptInferior(); - } - if (startMode() == AttachExternal || startMode() == AttachCrashedExternal) - postCommand(_("detach"), CB(handleExitHelper)); - else - postCommand(_("kill"), CB(handleExitHelper)); - } else { - exitDebugger2(); - } + m_outputCollector.shutdown(); + initializeVariables(); + m_gdbAdapter->shutdownAdapter(); } void GdbEngine::handleExitHelper(const GdbResultRecord &, const QVariant &) @@ -4316,6 +4305,7 @@ void GdbEngine::handleInferiorStarted() void GdbEngine::handleInferiorShutDown() { debugMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN")); + qq->notifyInferiorExited(); } void GdbEngine::handleInferiorShutdownFailed(const QString &msg) @@ -4325,6 +4315,18 @@ void GdbEngine::handleInferiorShutdownFailed(const QString &msg) tr("Inferior shutdown failed:\n") + msg); } +void GdbEngine::handleAdapterShutDown() +{ + debugMessage(_("ADAPTER SUCCESSFULLY SHUT DOWN")); +} + +void GdbEngine::handleAdapterShutdownFailed(const QString &msg) +{ + debugMessage(_("ADAPTER SHUTDOWN FAILED")); + QMessageBox::critical(mainWindow(), tr("Error"), + tr("Inferior shutdown failed:\n") + msg); +} + // // Factory // diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index b14e59ed001..71609c99350 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -214,6 +214,11 @@ private: AdapterCallback callback, const char *callbackName, const QVariant &cookie = QVariant()); + void postCommand(const QString &command, + GdbCommandFlags flags, + AdapterCallback callback, + const char *callbackName, + const QVariant &cookie = QVariant()); void postCommandHelper(const GdbCommand &cmd); void setTokenBarrier(); diff --git a/src/plugins/debugger/gdb/plaingdbadapter.cpp b/src/plugins/debugger/gdb/plaingdbadapter.cpp index 6f0f2b5a26b..bb27883818f 100644 --- a/src/plugins/debugger/gdb/plaingdbadapter.cpp +++ b/src/plugins/debugger/gdb/plaingdbadapter.cpp @@ -57,6 +57,7 @@ namespace Internal { PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent) : AbstractGdbAdapter(engine, parent) { + QTC_ASSERT(state() == AdapterNotRunning, qDebug() << state()); connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), this, SIGNAL(error(QProcess::ProcessError))); connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), @@ -64,9 +65,9 @@ PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent) connect(&m_gdbProc, SIGNAL(readyReadStandardError()), this, SIGNAL(readyReadStandardError())); connect(&m_gdbProc, SIGNAL(started()), - this, SIGNAL(adapterStarted())); + this, SLOT(handleGdbStarted())); connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(handleFinished(int, QProcess::ExitStatus))); + this, SLOT(handleGdbFinished(int, QProcess::ExitStatus))); m_stubProc.setMode(Core::Utils::ConsoleProcess::Debug); #ifdef Q_OS_UNIX @@ -84,6 +85,8 @@ PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent) void PlainGdbAdapter::startAdapter(const DebuggerStartParametersPtr &sp) { + QTC_ASSERT(state() == AdapterNotRunning, qDebug() << state()); + setState(AdapterStarting); debugMessage(_("TRYING TO START ADAPTER")); m_startParameters = sp; @@ -121,10 +124,20 @@ void PlainGdbAdapter::startAdapter(const DebuggerStartParametersPtr &sp) m_gdbProc.start(location, gdbArgs); } +void PlainGdbAdapter::handleGdbStarted() +{ + QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); + setState(AdapterStarted); + emit adapterStarted(); +} + void PlainGdbAdapter::prepareInferior() { + QTC_ASSERT(state() == AdapterStarted, qDebug() << state()); + setState(InferiorPreparing); if (!m_startParameters->processArgs.isEmpty()) - m_engine->postCommand(_("-exec-arguments ") + m_startParameters->processArgs.join(_(" "))); + m_engine->postCommand(_("-exec-arguments ") + + m_startParameters->processArgs.join(_(" "))); QFileInfo fi(m_engine->startParameters().executable); m_engine->postCommand(_("-file-exec-and-symbols \"%1\"").arg(fi.absoluteFilePath()), CB(handleFileExecAndSymbols)); @@ -132,18 +145,23 @@ void PlainGdbAdapter::prepareInferior() void PlainGdbAdapter::handleFileExecAndSymbols(const GdbResultRecord &response, const QVariant &) { + QTC_ASSERT(state() == InferiorPreparing, qDebug() << state()); if (response.resultClass == GdbResultDone) { //m_breakHandler->clearBreakMarkers(); + setState(InferiorPrepared); emit inferiorPrepared(); } else if (response.resultClass == GdbResultError) { QString msg = tr("Starting executable failed:\n") + __(response.data.findChild("msg").data()); + setState(InferiorPreparationFailed); emit inferiorPreparationFailed(msg); } } void PlainGdbAdapter::startInferior() { + QTC_ASSERT(state() == InferiorPrepared, qDebug() << state()); + setState(InferiorStarting); m_engine->postCommand(_("-exec-run"), CB(handleExecRun)); /* #ifdef Q_OS_MAC @@ -163,6 +181,7 @@ void PlainGdbAdapter::startInferior() void PlainGdbAdapter::handleInfoTarget(const GdbResultRecord &response, const QVariant &) { + QTC_ASSERT(state() == AdapterNotRunning, qDebug() << state()); #if defined(Q_OS_MAC) Q_UNUSED(response) #else @@ -190,13 +209,16 @@ void PlainGdbAdapter::handleInfoTarget(const GdbResultRecord &response, const QV void PlainGdbAdapter::handleExecRun(const GdbResultRecord &response, const QVariant &) { + QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); if (response.resultClass == GdbResultRunning) { + setState(InferiorStarted); emit inferiorStarted(); } else { QTC_ASSERT(response.resultClass == GdbResultError, /**/); const QByteArray &msg = response.data.findChild("msg").data(); //QTC_ASSERT(status() == DebuggerInferiorRunning, /**/); //interruptInferior(); + setState(InferiorStartFailed); emit inferiorStartFailed(msg); } } @@ -221,26 +243,57 @@ void PlainGdbAdapter::interruptInferior() void PlainGdbAdapter::shutdownAdapter() { - m_engine->postCommand(_("-gdb-exit"), CB(handleExit)); - // 20s can easily happen when loading webkit debug information - if (!m_gdbProc.waitForFinished(20000)) { - debugMessage(_("FORCING TERMINATION: %1") - .arg(state())); + if (state() == InferiorStarted) { + setState(InferiorShuttingDown); + m_engine->postCommand(_("kill"), CB(handleKill)); + return; + } + + if (state() == InferiorShutDown) { + setState(AdapterShuttingDown); + m_engine->postCommand(_("-gdb-exit"), CB(handleExit)); + return; + } + +/* + if (state() == InferiorShutdownFailed) { m_gdbProc.terminate(); + // 20s can easily happen when loading webkit debug information m_gdbProc.waitForFinished(20000); + setState(AdapterShuttingDown); + debugMessage(_("FORCING TERMINATION: %1") + .arg(state())); + if (state() != QProcess::NotRunning) { + debugMessage(_("PROBLEM STOPPING DEBUGGER: STATE %1") + .arg(state())); + m_gdbProc.kill(); + } + m_engine->postCommand(_("-gdb-exit"), CB(handleExit)); + return; } - if (state() != QProcess::NotRunning) { - debugMessage(_("PROBLEM STOPPING DEBUGGER: STATE %1") - .arg(state())); - m_gdbProc.kill(); +*/ + QTC_ASSERT(state() == AdapterNotRunning, qDebug() << state()); +} + +void PlainGdbAdapter::handleKill(const GdbResultRecord &response, const QVariant &) +{ + if (response.resultClass == GdbResultDone) { + setState(InferiorShutDown); + emit inferiorShutDown(); + shutdownAdapter(); // re-iterate... + } else if (response.resultClass == GdbResultError) { + QString msg = tr("Inferior process could not be stopped:\n") + + __(response.data.findChild("msg").data()); + setState(InferiorShutdownFailed); + emit inferiorShutdownFailed(msg); } } void PlainGdbAdapter::handleExit(const GdbResultRecord &response, const QVariant &) { if (response.resultClass == GdbResultDone) { - emit adapterShutDown(); + // don't set state here, this will be handled in handleGdbFinished() } else if (response.resultClass == GdbResultError) { QString msg = tr("Gdb process could not be stopped:\n") + __(response.data.findChild("msg").data()); @@ -248,9 +301,11 @@ void PlainGdbAdapter::handleExit(const GdbResultRecord &response, const QVariant } } -void PlainGdbAdapter::handleFinished(int, QProcess::ExitStatus) +void PlainGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus) { - debugMessage(_("GDB PROESS FINISHED")); + debugMessage(_("GDB PROESS FINISHED")); + setState(AdapterNotRunning); + emit adapterShutDown(); } void PlainGdbAdapter::shutdownInferior() @@ -287,5 +342,6 @@ void PlainGdbAdapter::emitAdapterStartFailed(const QString &msg) m_stubProc.blockSignals(false); emit adapterStartFailed(msg); } + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/gdb/plaingdbadapter.h b/src/plugins/debugger/gdb/plaingdbadapter.h index de6f8d68d61..cc8c93341be 100644 --- a/src/plugins/debugger/gdb/plaingdbadapter.h +++ b/src/plugins/debugger/gdb/plaingdbadapter.h @@ -57,7 +57,6 @@ public: //void kill() { m_gdbProc.kill(); } //void terminate() { m_gdbProc.terminate(); } - QProcess::ProcessState state() const { return m_gdbProc.state(); } QString errorString() const { return m_gdbProc.errorString(); } QByteArray readAllStandardError() { return m_gdbProc.readAllStandardError(); } QByteArray readAllStandardOutput() { return m_gdbProc.readAllStandardOutput(); } @@ -75,6 +74,7 @@ public: private: void handleFileExecAndSymbols(const GdbResultRecord &, const QVariant &); + void handleKill(const GdbResultRecord &, const QVariant &); void handleExit(const GdbResultRecord &, const QVariant &); void handleStubAttached(const GdbResultRecord &, const QVariant &); void handleExecRun(const GdbResultRecord &response, const QVariant &); @@ -82,7 +82,8 @@ private: void debugMessage(const QString &msg) { m_engine->debugMessage(msg); } void emitAdapterStartFailed(const QString &msg); - Q_SLOT void handleFinished(int, QProcess::ExitStatus); + Q_SLOT void handleGdbFinished(int, QProcess::ExitStatus); + Q_SLOT void handleGdbStarted(); Q_SLOT void stubStarted(); Q_SLOT void stubError(const QString &msg); diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp index bab0c82babf..efce356ebe2 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp @@ -1488,9 +1488,10 @@ bool TrkGdbAdapter::waitForFinished(int msecs) return m_gdbProc.waitForFinished(msecs); } -QProcess::ProcessState TrkGdbAdapter::state() const +GdbAdapterState TrkGdbAdapter::state() const { - return m_gdbProc.state(); + //return m_gdbProc.state(); + return AdapterNotRunning; // FIXME } QString TrkGdbAdapter::errorString() const diff --git a/src/plugins/debugger/gdb/trkgdbadapter.h b/src/plugins/debugger/gdb/trkgdbadapter.h index 0944e7aec73..43ae3a4633a 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.h +++ b/src/plugins/debugger/gdb/trkgdbadapter.h @@ -111,7 +111,7 @@ public: void kill(); void terminate(); bool waitForFinished(int msecs = 30000); - QProcess::ProcessState state() const; + GdbAdapterState state() const; QString errorString() const; QByteArray readAllStandardError(); QByteArray readAllStandardOutput(); -- GitLab