From b4a79218326b622a0c2dd8918fb6e2824583070c Mon Sep 17 00:00:00 2001
From: hjk <qtc-committer@nokia.com>
Date: Tue, 17 Feb 2009 17:42:08 +0100
Subject: [PATCH]     Fixes:    debugger: work on process logic

Conflicts:

	src/plugins/debugger/gdbengine.cpp
---
 src/plugins/debugger/debuggermanager.cpp |  12 +++
 src/plugins/debugger/debuggermanager.h   |   2 +
 src/plugins/debugger/gdbengine.cpp       | 105 +++++++++++++++--------
 src/plugins/debugger/gdbengine.h         |  11 ++-
 4 files changed, 89 insertions(+), 41 deletions(-)

diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index 660448a6bcc..9130d57c54b 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -543,6 +543,12 @@ void DebuggerManager::notifyStartupFinished()
     showStatusMessage(tr("Startup finished. Debugger ready."), -1);
 }
 
+void DebuggerManager::notifyInferiorStopRequested()
+{
+    setStatus(DebuggerInferiorStopRequested);
+    showStatusMessage(tr("Stop requested..."), 5000);
+}
+
 void DebuggerManager::notifyInferiorStopped()
 {
     resetLocation();
@@ -657,6 +663,12 @@ void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
 {
     QTC_ASSERT(m_engine, return);
     QTC_ASSERT(m_breakHandler, return);
+    if (status() != DebuggerInferiorRunning && status() != DebuggerInferiorStopped) {
+        showStatusMessage(tr("Changing breakpoint state requires either a "
+            "fully running or fully stopped application."));
+        return;
+    }
+
     int index = m_breakHandler->indexOf(fileName, lineNumber);
     if (index == -1)
         m_breakHandler->setBreakpoint(fileName, lineNumber);
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 8af4a683378..636187d68cd 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -151,6 +151,7 @@ private:
 
     // called from the engines after successful startup
     virtual void notifyStartupFinished() = 0; 
+    virtual void notifyInferiorStopRequested() = 0;
     virtual void notifyInferiorStopped() = 0; 
     virtual void notifyInferiorUpdateFinished() = 0; 
     virtual void notifyInferiorRunningRequested() = 0;
@@ -339,6 +340,7 @@ private:
     void notifyInferiorStopped();
     void notifyInferiorUpdateFinished();
     void notifyInferiorRunningRequested();
+    void notifyInferiorStopRequested();
     void notifyInferiorRunning();
     void notifyInferiorExited();
     void notifyInferiorPidChanged(int);
diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp
index ae80da5b716..6f41c83379d 100644
--- a/src/plugins/debugger/gdbengine.cpp
+++ b/src/plugins/debugger/gdbengine.cpp
@@ -115,6 +115,7 @@ enum GdbCommandType
     GdbInfoThreads,
     GdbQueryDataDumper1,
     GdbQueryDataDumper2,
+    GdbTemporaryContinue,
 
     BreakCondition = 200,
     BreakEnablePending,
@@ -305,6 +306,7 @@ void GdbEngine::initializeVariables()
     m_pendingRequests = 0;
     m_waitingForBreakpointSynchronizationToContinue = false;
     m_waitingForFirstBreakpointToBeHit = false;
+    m_commandsToRunOnTemporaryBreak.clear();
 }
 
 void GdbEngine::gdbProcError(QProcess::ProcessError error)
@@ -650,22 +652,29 @@ void GdbEngine::readGdbStandardOutput()
 
 void GdbEngine::interruptInferior()
 {
-    if (m_gdbProc.state() == QProcess::NotRunning)
+    qq->notifyInferiorStopRequested();
+    if (m_gdbProc.state() == QProcess::NotRunning) {
+        debugMessage("TRYING TO INTERRUPT INFERIOR WITHOUT RUNNING GDB");
+        qq->notifyInferiorExited();
         return;
+    }
 
     if (q->m_attachedPID > 0) {
-        if (interruptProcess(q->m_attachedPID))
-            qq->notifyInferiorStopped();
+        if (!interruptProcess(q->m_attachedPID))
+        //    qq->notifyInferiorStopped();
+        //else
+            debugMessage(QString("CANNOT INTERRUPT %1").arg(q->m_attachedPID));
         return;
     }
 
 #ifdef Q_OS_MAC
     sendCommand("-exec-interrupt", GdbExecInterrupt);
-    qq->notifyInferiorStopped();
+    //qq->notifyInferiorStopped();
 #else
-    debugMessage(QString("CANNOT STOP INFERIOR"));
-    if (interruptChildProcess(m_gdbProc.pid()))
-        qq->notifyInferiorStopped();
+    if (!interruptChildProcess(m_gdbProc.pid()))
+    //    qq->notifyInferiorStopped();
+    //else
+        debugMessage(QString("CANNOT STOP INFERIOR"));
 #endif
 }
 
@@ -684,27 +693,19 @@ void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0)
 }
 
 void GdbEngine::sendSynchronizedCommand(const QString & command,
-    int type, const QVariant &cookie, bool needStop)
+    int type, const QVariant &cookie, StopNeeded needStop)
 {
-    sendCommand(command, type, cookie, needStop, true);
+    sendCommand(command, type, cookie, needStop, Synchronized);
 }
 
 void GdbEngine::sendCommand(const QString &command, int type,
-    const QVariant &cookie, bool needStop, bool synchronized)
+    const QVariant &cookie, StopNeeded needStop, Synchronization synchronized)
 {
     if (m_gdbProc.state() == QProcess::NotRunning) {
         debugMessage("NO GDB PROCESS RUNNING, CMD IGNORED: " + command);
         return;
     }
 
-    bool temporarilyStopped = false;
-    if (needStop && q->status() == DebuggerInferiorRunning) {
-        q->showStatusMessage(tr("Temporarily stopped"));
-        interruptInferior();
-        temporarilyStopped = true;
-    }
-
-    ++currentToken();
     if (synchronized) {
         ++m_pendingRequests;
         PENDING_DEBUG("   TYPE " << type << " INCREMENTS PENDING TO: "
@@ -717,26 +718,30 @@ void GdbEngine::sendCommand(const QString &command, int type,
     GdbCookie cmd;
     cmd.synchronized = synchronized;
     cmd.command = command;
-    cmd.command = QString::number(currentToken()) + cmd.command;
-    if (cmd.command.contains("%1"))
-        cmd.command = cmd.command.arg(currentToken());
     cmd.type = type;
     cmd.cookie = cookie;
 
-    m_cookieForToken[currentToken()] = cmd;
+    if (needStop && q->status() != DebuggerInferiorStopped
+            && q->status() != DebuggerProcessStartingUp) {
+        // queue the commands that we cannot send at once
+        QTC_ASSERT(q->status() == DebuggerInferiorRunning,
+            qDebug() << "STATUS: " << q->status());
+        q->showStatusMessage(tr("Stopping temporarily."));
+        debugMessage("QUEUING COMMAND " + cmd.command);
+        m_commandsToRunOnTemporaryBreak.append(cmd);
+        interruptInferior();
+    } else if (!command.isEmpty()) {
+        ++currentToken();
+        m_cookieForToken[currentToken()] = cmd;
+        cmd.command = QString::number(currentToken()) + cmd.command;
+        if (cmd.command.contains("%1"))
+            cmd.command = cmd.command.arg(currentToken());
 
-    if (!command.isEmpty()) {
         m_gdbProc.write(cmd.command.toLatin1() + "\r\n");
         //emit gdbInputAvailable(QString(), "         " +  currentTime());
         //emit gdbInputAvailable(QString(), "[" + currentTime() + "]    " + cmd.command);
         emit gdbInputAvailable(QString(), cmd.command);
     }
-
-    if (temporarilyStopped)
-        sendCommand("-exec-continue");
-
-    // slows down
-    //qApp->processEvents();
 }
 
 void GdbEngine::handleResultRecord(const GdbResultRecord &record)
@@ -822,6 +827,7 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type,
             //handleExecRunToFunction(record);
             break;
         case GdbExecInterrupt:
+            qq->notifyInferiorStopped();
             break;
         case GdbExecJumpToLine:
             handleExecJumpToLine(record);
@@ -844,6 +850,10 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type,
         case GdbQueryDataDumper2:
             handleQueryDataDumper2(record);
             break;
+        case GdbTemporaryContinue:
+            continueInferior();
+            q->showStatusMessage(tr("Continuing after temporary stop."));
+            break;
 
         case BreakList:
             handleBreakList(record);
@@ -1104,6 +1114,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
     //MAC: bool isFirstStop = data.findChild("bkptno").data() == "1";
     //!MAC: startSymbolName == data.findChild("frame").findChild("func")
     if (m_waitingForFirstBreakpointToBeHit) {
+        qq->notifyInferiorStopped();
         m_waitingForFirstBreakpointToBeHit = false;
         //
         // that's the "early stop"
@@ -1143,6 +1154,23 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
         return;
     }
 
+    if (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
+        QTC_ASSERT(q->status() == DebuggerInferiorStopRequested, 
+            qDebug() << "STATUS: " << q->status())
+        qq->notifyInferiorStopped();
+        q->showStatusMessage(tr("Temporarily stopped."));
+        // FIXME: racy
+        foreach (const GdbCookie &cmd, m_commandsToRunOnTemporaryBreak) {
+            debugMessage(QString("RUNNING QUEUED COMMAND %1 %2")
+                .arg(cmd.command).arg(cmd.type));
+            sendCommand(cmd.command, cmd.type, cmd.cookie);
+        }
+        sendCommand("p temporaryStop", GdbTemporaryContinue);
+        m_commandsToRunOnTemporaryBreak.clear();
+        q->showStatusMessage(tr("Handling queued commands."));
+        return;
+    }
+
     QString msg = data.findChild("consolestreamoutput").data();
     if (msg.contains("Stopped due to shared library event") || reason.isEmpty()) {
         if (qq->wantsSelectedPluginBreakpoints()) {
@@ -1619,8 +1647,8 @@ void GdbEngine::continueInferior()
 {
     q->resetLocation();
     setTokenBarrier();
-    qq->notifyInferiorRunningRequested();
     emit gdbInputAvailable(QString(), QString());
+    qq->notifyInferiorRunningRequested();
     sendCommand("-exec-continue", GdbExecContinue);
 }
 
@@ -1636,8 +1664,8 @@ void GdbEngine::handleStart(const GdbResultRecord &response)
             //debugMessage("STREAM: " + msg + " " + needle.cap(1));
             sendCommand("tbreak *0x" + needle.cap(1));
             m_waitingForFirstBreakpointToBeHit = true;
-            sendCommand("-exec-run");
             qq->notifyInferiorRunningRequested();
+            sendCommand("-exec-run");
         } else {
             debugMessage("PARSING START ADDRESS FAILED: " + msg);
         }
@@ -1649,8 +1677,8 @@ void GdbEngine::handleStart(const GdbResultRecord &response)
 void GdbEngine::stepExec()
 {
     setTokenBarrier();
-    qq->notifyInferiorRunningRequested();
     emit gdbInputAvailable(QString(), QString());
+    qq->notifyInferiorRunningRequested();
     sendCommand("-exec-step", GdbExecStep);
 }
 
@@ -1671,8 +1699,8 @@ void GdbEngine::stepOutExec()
 void GdbEngine::nextExec()
 {
     setTokenBarrier();
-    qq->notifyInferiorRunningRequested();
     emit gdbInputAvailable(QString(), QString());
+    qq->notifyInferiorRunningRequested();
     sendCommand("-exec-next", GdbExecNext);
 }
 
@@ -1865,8 +1893,8 @@ void GdbEngine::sendInsertBreakpoint(int index)
     //    cmd += "-c " + data->condition + " ";
     cmd += where;
 #endif
-    sendCommand(cmd, BreakInsert, index, true);
-    //processQueueAndContinue();
+    debugMessage(QString("Current state: %1").arg(q->status()));
+    sendCommand(cmd, BreakInsert, index, NeedsStop);
 }
 
 void GdbEngine::handleBreakList(const GdbResultRecord &record)
@@ -2103,10 +2131,11 @@ void GdbEngine::attemptBreakpointSynchronization()
 
     foreach (BreakpointData *data, handler->takeRemovedBreakpoints()) {
         QString bpNumber = data->bpNumber;
+        debugMessage(QString("DELETING BP %1 IN %2").arg(bpNumber)
+            .arg(data->markerFileName));
         if (!bpNumber.trimmed().isEmpty())
-            sendCommand("-break-delete " + bpNumber, BreakDelete, 0, true);
-        //else
-        //    qDebug() << "BP HAS NO NUMBER: " << data->markerFileName;
+            sendCommand("-break-delete " + bpNumber, BreakDelete, QVariant(),
+                NeedsStop);
         delete data;
     }
 
diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h
index ee5de645c3d..0b59af8b1c7 100644
--- a/src/plugins/debugger/gdbengine.h
+++ b/src/plugins/debugger/gdbengine.h
@@ -158,12 +158,15 @@ private:
     // queue". resultNeeded == true increments m_pendingResults on
     // send and decrements on receipt, effectively preventing 
     // watch model updates before everything is finished.
-    void sendCommand(const QString & command,
+    enum StopNeeded { DoesNotNeedStop, NeedsStop };
+    enum Synchronization { NotSynchronized, Synchronized };
+    void sendCommand(const QString &command,
         int type = 0, const QVariant &cookie = QVariant(),
-        bool needStop = false, bool synchronized = false);
+        StopNeeded needStop = DoesNotNeedStop,
+        Synchronization synchronized = NotSynchronized);
     void sendSynchronizedCommand(const QString & command,
         int type = 0, const QVariant &cookie = QVariant(),
-        bool needStop = false);
+        StopNeeded needStop = DoesNotNeedStop);
 
     void setTokenBarrier();
 
@@ -335,6 +338,8 @@ private:
     bool m_waitingForFirstBreakpointToBeHit;
     bool m_modulesListOutdated;
 
+    QList<GdbCookie> m_commandsToRunOnTemporaryBreak;
+
     DebuggerManager *q;
     IDebuggerManagerAccessForEngines *qq;
 };
-- 
GitLab