From db68ca5b8d7454eb0429dc169d3cfff66c7226d4 Mon Sep 17 00:00:00 2001
From: con <qtc-committer@nokia.com>
Date: Wed, 6 Jan 2010 15:52:14 +0100
Subject: [PATCH] debugger: gracefully handle commands that might not produce
 output

(cherry picked from commit 1324a1c6004e1f0702d46a9adb4dc69631247e1a)

Conflicts:

	src/plugins/debugger/gdb/gdbengine.cpp
	src/plugins/debugger/gdb/gdbengine.h
---
 src/plugins/debugger/debuggermanager.cpp |  7 ++--
 src/plugins/debugger/debuggermanager.h   |  8 ++--
 src/plugins/debugger/gdb/gdbengine.cpp   | 51 +++++++++++++++++++-----
 src/plugins/debugger/gdb/gdbengine.h     | 14 ++++---
 4 files changed, 59 insertions(+), 21 deletions(-)

diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index f14d10723e4..9a836aa8999 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -1541,13 +1541,14 @@ void DebuggerManager::setSessionValue(const QString &name, const QVariant &value
     emit setSessionValueRequested(name, value);
 }
 
-void DebuggerManager::showMessageBox(int icon,
-    const QString &title, const QString &text)
+QMessageBox *DebuggerManager::showMessageBox(int icon, const QString &title,
+    const QString &text, int buttons)
 {
     QMessageBox *mb = new QMessageBox(QMessageBox::Icon(icon),
-        title, text, QMessageBox::NoButton, mainWindow());
+        title, text, QMessageBox::StandardButtons(buttons), mainWindow());
     mb->setAttribute(Qt::WA_DeleteOnClose);
     mb->show();
+    return mb;
 }
 
 DebuggerState DebuggerManager::state() const
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 05639618b2e..045d99fe29e 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -39,11 +39,12 @@
 #include <QtCore/QVariant>
 
 QT_BEGIN_NAMESPACE
+class QAbstractItemModel;
 class QAction;
+class QDebug;
 class QDockWidget;
 class QLabel;
-class QDebug;
-class QAbstractItemModel;
+class QMessageBox;
 class QPoint;
 class QVariant;
 QT_END_NAMESPACE
@@ -177,7 +178,8 @@ public:
     DebuggerStartParametersPtr startParameters() const;
     qint64 inferiorPid() const;
 
-    void showMessageBox(int icon, const QString &title, const QString &text);
+    QMessageBox *showMessageBox(int icon, const QString &title, const QString &text,
+        int buttons = 0);
 
     bool debuggerActionsEnabled() const;
 
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index a2f97db8f28..070ab9a82ce 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -617,7 +617,7 @@ void GdbEngine::readGdbStandardError()
 
 void GdbEngine::readGdbStandardOutput()
 {
-    if (m_commandTimer->isActive())
+    if (m_commandTimer->isActive()) 
         m_commandTimer->start(); // Retrigger
 
     int newstart = 0;
@@ -816,19 +816,48 @@ void GdbEngine::flushCommand(const GdbCommand &cmd0)
         setState(InferiorShuttingDown);
 }
 
+int GdbEngine::commandTimeoutTime() const
+{
+    int time = theDebuggerAction(GdbWatchdogTimeout)->value().toInt();
+    return 1000 * qMax(20, time);
+}
+
 void GdbEngine::commandTimeout()
 {
-    // FIXME this needs a proper message box
-    debugMessage(_("TIMED OUT WAITING FOR GDB REPLY. COMMANDS STILL IN PROGRESS:"));
+    qDebug("TIMEOUT");
     QList<int> keys = m_cookieForToken.keys();
     qSort(keys);
+    bool killIt = false;
     foreach (int key, keys) {
-        const GdbCommand &cmd = m_cookieForToken[key];
+        const GdbCommand &cmd = m_cookieForToken.value(key);
+        if (!(cmd.flags & NonCriticalResponse))
+            killIt = true;
         debugMessage(_("  %1: %2 => %3").arg(key).arg(cmd.command).arg(_(cmd.callbackName)));
     }
-    // This is an entirely undefined state, so we just pull the emergency brake.
-    setState(EngineShuttingDown, true);
-    m_gdbProc.kill();
+    if (killIt) {
+        debugMessage(_("TIMED OUT WAITING FOR GDB REPLY. COMMANDS STILL IN PROGRESS:"));
+        int timeOut = m_commandTimer->interval();
+        //m_commandTimer->stop();
+        QString msg = tr("The gdb process has not produced any response "
+            "to a command within %1 seconds. This may been it is stuck "
+            "in an endless loop or taking longer than expected to perform "
+            "the operation it was reqested.\nYou have a choice of waiting "
+            "longer or abort debugging.").arg(timeOut);
+        QMessageBox *mb = showMessageBox(QMessageBox::Critical,
+            tr("Gdb not responding"), msg, 
+            QMessageBox::Ok | QMessageBox::Cancel);
+        mb->button(QMessageBox::Cancel)->setText(tr("Give gdb more time"));
+        mb->button(QMessageBox::Ok)->setText(tr("Stop debugging"));
+        if (mb->exec() == QMessageBox::Ok) {
+            debugMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
+            // This is an undefined state, so we just pull the emergency brake.
+            manager()->watchHandler()->endCycle();
+            setState(EngineShuttingDown, true);
+            m_gdbProc.kill();
+        } else {
+            debugMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER"));
+        }
+    }
 }
 
 void GdbEngine::handleResultRecord(GdbResponse *response)
@@ -2960,7 +2989,7 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren)
             <<',' <<  addr << ',' << (dumpChildren ? "1" : "0")
             << ',' << extraArgs.join(QString(_c(','))) <<  ')';
 
-    postCommand(cmd, WatchUpdate | EmbedToken);
+    postCommand(cmd, WatchUpdate | EmbedToken | NonCriticalResponse);
 
     showStatusMessage(msgRetrievingWatchData(m_pendingRequests + 1), 10000);
 
@@ -4347,6 +4376,7 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QStr
         SLOT(readGdbStandardError()));
 
     debugMessage(_("GDB STARTED, INITIALIZING IT"));
+    m_commandTimer->setInterval(commandTimeoutTime());
 
     postCommand(_("show version"), CB(handleShowVersion));
     postCommand(_("-interpreter-exec console \"help bb\""),
@@ -4573,9 +4603,10 @@ void GdbEngine::addOptionPages(QList<Core::IOptionsPage*> *opts) const
     opts->push_back(new TrkOptionsPage(m_trkOptions));
 }
 
-void GdbEngine::showMessageBox(int icon, const QString &title, const QString &text)
+QMessageBox * GdbEngine::showMessageBox(int icon, const QString &title,
+    const QString &text, int buttons)
 {
-    m_manager->showMessageBox(icon, title, text);
+    return m_manager->showMessageBox(icon, title, text, buttons);
 }
 
 bool GdbEngine::isSynchroneous() const
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index 1d6b1666eb5..3707bf66cc0 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -47,11 +47,12 @@
 #include <QtCore/QVariant>
 
 QT_BEGIN_NAMESPACE
-class QAction;
 class QAbstractItemModel;
+class QAction;
+class QMainWindow;
+class QMessageBox;
 class QTimer;
 class QWidget;
-class QMainWindow;
 QT_END_NAMESPACE
 
 namespace Debugger {
@@ -176,10 +177,11 @@ private: ////////// Gdb Command Management //////////
         Discardable = 2,  // No need to wait for the reply before continuing inferior
         RebuildModel = 4, // Trigger model rebuild when no such commands are pending any more
         WatchUpdate = Discardable | RebuildModel,
-        EmbedToken = 8,   // Expand %1 in the command to the command token
+        NonCriticalResponse = 8,  // We can live without recieving an answer
         RunRequest = 16,  // Callback expects GdbResultRunning instead of GdbResultDone
         ExitRequest = 32, // Callback expects GdbResultExit instead of GdbResultDone
-        LosesChild = 64   // Auto-set inferior shutdown related states
+        LosesChild = 64,   // Auto-set inferior shutdown related states
+        EmbedToken = 128   // Expand %1 in the command to the command token
     };
     Q_DECLARE_FLAGS(GdbCommandFlags, GdbCommandFlag)
     private:
@@ -233,6 +235,7 @@ private: ////////// Gdb Command Management //////////
     void setTokenBarrier();
 
     QHash<int, GdbCommand> m_cookieForToken;
+    int commandTimeoutTime() const;
     QTimer *m_commandTimer;
 
     QByteArray m_pendingConsoleStreamOutput;
@@ -476,7 +479,8 @@ private: ////////// Dumper Management //////////
 private: ////////// Convenience Functions //////////
 
     QString errorMessage(QProcess::ProcessError error);
-    void showMessageBox(int icon, const QString &title, const QString &text);
+    QMessageBox *showMessageBox(int icon, const QString &title, const QString &text,
+        int buttons = 0);
     void debugMessage(const QString &msg);
     QMainWindow *mainWindow() const;
 };
-- 
GitLab