diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 5812a3202911c5ff89d03b203dc19f5215f2f0a9..b136b2aeeed49a9dd4f75b549512add0ad0f1aec 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -1551,13 +1551,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 bcc21ba4b8e785926cdbb412420d6afe3b476741..9763b362d92a5246ebf768ce3309361d8865a20e 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 @@ -180,7 +181,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 def3ae40c1744ed0b4150729d6f69f6f865ce447..147e7f74e585227ad3b38168ace2b8a5298e4b14 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -614,7 +614,7 @@ void GdbEngine::readGdbStandardError() void GdbEngine::readGdbStandardOutput() { - if (m_commandTimer->isActive()) + if (m_commandTimer->isActive()) m_commandTimer->start(); // Retrigger int newstart = 0; @@ -811,19 +811,47 @@ 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. - manager()->watchHandler()->endCycle(); - 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(); + m_gdbProc.kill(); + } else { + debugMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER")); + } + } } void GdbEngine::handleResultRecord(GdbResponse *response) @@ -2969,7 +2997,7 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren) protocol << ",0," << addr << ',' << (dumpChildren ? "1" : "0") << ',' << extraArgs.join(QString(_c(','))) << ')'; - postCommand(cmd, WatchUpdate); + postCommand(cmd, WatchUpdate | NonCriticalResponse); showStatusMessage(msgRetrievingWatchData(m_pendingRequests + 1), 10000); @@ -4388,13 +4416,14 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QStr SLOT(readGdbStandardError())); debugMessage(_("GDB STARTED, INITIALIZING IT")); - int timeOut = theDebuggerAction(GdbWatchdogTimeout)->value().toInt(); - m_commandTimer->setInterval(1000 * qMax(20, timeOut)); + m_commandTimer->setInterval(commandTimeoutTime()); postCommand(_("show version"), CB(handleShowVersion)); - postCommand(_("python execfile('%1dumper.py')").arg(dumperSourcePath)); - postCommand(_("python execfile('%1gdbmacros.py')").arg(dumperSourcePath)); + postCommand(_("python execfile('%1dumper.py')").arg(dumperSourcePath), + NonCriticalResponse); + postCommand(_("python execfile('%1gdbmacros.py')").arg(dumperSourcePath), + NonCriticalResponse); postCommand(_("-interpreter-exec console \"help bb\""), CB(handleIsSynchroneous)); @@ -4620,9 +4649,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 fb89a9a624a2f072af8d5b136d97472624915851..06312b3ed113988fab0686449d0e4387fe871ffe 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 { @@ -177,6 +178,7 @@ 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, + 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 @@ -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; };