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