QmlCppDebugger: Decouple states of engines

The main engine now follows mostly the state of the gdb engine,
only if a breakpoint is hit/while stepping the state of the qml
engine is used. This allows us to hit C++ breakpoints at any time
(also when the qml engine hasn't been able to connect yet), and
also fixes the invalid transition warnings.

Change-Id: If67a56fd28b098952be2606d0a46e04c27835f66
Reviewed-on: http://codereview.qt-project.org/5897
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
This commit is contained in:
Kai Koehne
2011-09-29 16:49:18 +02:00
parent 21e25b835b
commit 732334a0b8
3 changed files with 137 additions and 149 deletions

View File

@@ -1208,6 +1208,12 @@ void DebuggerEngine::quitDebugger()
case InferiorRunOk: case InferiorRunOk:
d->doInterruptInferior(); d->doInterruptInferior();
break; break;
case EngineRunRequested:
notifyEngineRunFailed();
break;
case EngineRunFailed:
case DebuggerFinished:
break;
default: default:
// FIXME: We should disable the actions connected to that. // FIXME: We should disable the actions connected to that.
notifyInferiorIll(); notifyInferiorIll();

View File

@@ -283,16 +283,18 @@ void QmlCppEngine::updateAll()
void QmlCppEngine::attemptBreakpointSynchronization() void QmlCppEngine::attemptBreakpointSynchronization()
{ {
if (d->m_qmlEngine->state() == InferiorRunOk
|| d->m_qmlEngine->state() == InferiorRunRequested
|| d->m_qmlEngine->state() == InferiorStopOk
|| d->m_qmlEngine->state() == InferiorStopRequested) {
// We expect both engines to be set up correctly before hitting
// any breakpoints, therefore ignore any breakpoints that would
// be hit before QDeclarativeEngine is set up.
d->m_cppEngine->attemptBreakpointSynchronization(); d->m_cppEngine->attemptBreakpointSynchronization();
}
switch (d->m_qmlEngine->state()) {
case InferiorRunOk:
case InferiorRunRequested:
case InferiorStopOk: // fall through
case InferiorStopRequested:
d->m_qmlEngine->attemptBreakpointSynchronization(); d->m_qmlEngine->attemptBreakpointSynchronization();
break;
default:
break;
}
} }
bool QmlCppEngine::acceptsBreakpoint(BreakpointModelId id) const bool QmlCppEngine::acceptsBreakpoint(BreakpointModelId id) const
@@ -470,6 +472,7 @@ void QmlCppEngine::runEngine()
void QmlCppEngine::shutdownInferior() void QmlCppEngine::shutdownInferior()
{ {
EDEBUG("\nMASTER SHUTDOWN INFERIOR"); EDEBUG("\nMASTER SHUTDOWN INFERIOR");
d->m_cppEngine->quitDebugger();
d->m_qmlEngine->quitDebugger(); d->m_qmlEngine->quitDebugger();
} }
@@ -498,84 +501,63 @@ void QmlCppEngine::slaveEngineStateChanged
EDEBUG(" OTHER ENGINE: " << otherEngine << otherEngine->state()); EDEBUG(" OTHER ENGINE: " << otherEngine << otherEngine->state());
EDEBUG(" COMBINED ENGINE: " << this << state() << isDying()); EDEBUG(" COMBINED ENGINE: " << this << state() << isDying());
// Idea is to follow the state of the cpp engine,
// except where we are stepping in QML
if (slaveEngine == d->m_cppEngine) {
switch (newState) { switch (newState) {
case DebuggerNotReady: case DebuggerNotReady:
// Can this ever happen?
break; break;
case EngineSetupRequested: case EngineSetupRequested:
QTC_CHECK(state() == EngineSetupRequested);
break; break;
case EngineSetupFailed: case EngineSetupFailed:
qmlEngine()->quitDebugger();
notifyEngineSetupFailed(); notifyEngineSetupFailed();
break; break;
case EngineSetupOk: case EngineSetupOk:
if (otherEngine->state() == EngineSetupOk)
notifyEngineSetupOk(); notifyEngineSetupOk();
else
EDEBUG("... WAITING FOR OTHER ENGINE SETUP...");
break; break;
case InferiorSetupRequested: case InferiorSetupRequested:
break; break;
case InferiorSetupFailed: case InferiorSetupFailed:
if (otherEngine->state() == InferiorRunOk) qmlEngine()->quitDebugger();
otherEngine->quitDebugger();
else
notifyInferiorSetupFailed(); notifyInferiorSetupFailed();
break; break;
case InferiorSetupOk: case InferiorSetupOk:
if (otherEngine->state() == InferiorSetupOk)
notifyInferiorSetupOk(); notifyInferiorSetupOk();
else
EDEBUG("... WAITING FOR OTHER INFERIOR SETUP...");
break; break;
case EngineRunRequested: case EngineRunRequested:
break; break;
case EngineRunFailed: case EngineRunFailed:
if (otherEngine->state() == InferiorRunOk) qmlEngine()->quitDebugger();
otherEngine->quitDebugger();
else
notifyEngineRunFailed(); notifyEngineRunFailed();
break; break;
case InferiorUnrunnable: case InferiorUnrunnable:
notifyInferiorUnrunnable();
break; break;
case InferiorRunRequested: case InferiorRunRequested:
break; break;
case InferiorRunOk: case InferiorRunOk:
if (state() == EngineRunRequested) { if (state() == EngineRunRequested)
if (otherEngine->state() == InferiorRunOk) {
attemptBreakpointSynchronization();
notifyEngineRunAndInferiorRunOk(); notifyEngineRunAndInferiorRunOk();
} else { else if (state() == InferiorRunRequested)
EDEBUG("... WAITING FOR OTHER INFERIOR RUN");
}
} else {
if (otherEngine->state() == InferiorRunOk) {
EDEBUG("PLANNED INFERIOR RUN");
if (state() == InferiorStopOk) {
notifyInferiorRunRequested();
}
notifyInferiorRunOk(); notifyInferiorRunOk();
} else if (otherEngine->state() == InferiorStopOk) {
EDEBUG("PLANNED SINGLE INFERIOR RUN");
} else {
EDEBUG(" **** INFERIOR RUN NOT OK ****");
}
}
break; break;
case InferiorRunFailed: case InferiorRunFailed:
qmlEngine()->quitDebugger();
notifyInferiorRunFailed(); notifyInferiorRunFailed();
break; break;
@@ -584,30 +566,28 @@ void QmlCppEngine::slaveEngineStateChanged
case InferiorStopOk: case InferiorStopOk:
if (isDying()) { if (isDying()) {
EDEBUG("... AN INFERIOR STOPPED DURING SHUTDOWN "); EDEBUG("... CPP ENGINE STOPPED DURING SHUTDOWN ");
if (state() == InferiorStopRequested) { if (state() == InferiorStopRequested)
notifyInferiorStopOk(); notifyInferiorStopOk();
}
} else { } else {
if (slaveEngine != d->m_activeEngine) { if (d->m_activeEngine != cppEngine()) {
QString engineName = slaveEngine == d->m_cppEngine showStatusMessage(tr("Cpp debugger activated"));
? QLatin1String("C++") : QLatin1String("QML"); d->m_activeEngine = cppEngine();
showStatusMessage(tr("%1 debugger activated").arg(engineName));
d->m_activeEngine = slaveEngine;
} }
if (otherEngine->state() == InferiorStopOk) { switch (state()) {
EDEBUG("... BOTH STOPPED "); case InferiorStopRequested:
} else if (otherEngine->state() == InferiorShutdownOk) { EDEBUG("... CPP ENGINE STOPPED EXPECTEDLY");
EDEBUG("... STOPP ");
} else if (state() == InferiorStopRequested) {
EDEBUG("... AN INFERIOR STOPPED EXPECTEDLY");
notifyInferiorStopOk(); notifyInferiorStopOk();
} else if (state() == EngineRunRequested) { break;
EDEBUG("... AN INFERIOR FAILED STARTUP, OTHER STOPPED EXPECTEDLY"); case EngineRunRequested:
// wait for failure notification from other engine EDEBUG("... CPP ENGINE STOPPED ON STARTUP");
} else { notifyEngineRunAndInferiorStopOk();
EDEBUG("... AN INFERIOR STOPPED SPONTANEOUSLY"); break;
default:
QTC_CHECK(state() == InferiorRunOk);
EDEBUG("... CPP ENGINE STOPPED SPONTANEOUSLY");
notifyInferiorSpontaneousStop(); notifyInferiorSpontaneousStop();
break;
} }
} }
break; break;
@@ -617,6 +597,8 @@ void QmlCppEngine::slaveEngineStateChanged
break; break;
case InferiorExitOk: case InferiorExitOk:
qmlEngine()->quitDebugger();
notifyInferiorExited();
break; break;
case InferiorShutdownRequested: case InferiorShutdownRequested:
@@ -627,45 +609,43 @@ void QmlCppEngine::slaveEngineStateChanged
break; break;
case InferiorShutdownOk: case InferiorShutdownOk:
if (otherEngine->state() == InferiorShutdownOk) { if (state() == InferiorShutdownRequested)
if (state() == InferiorRunOk)
notifyInferiorExited();
else
notifyInferiorShutdownOk(); notifyInferiorShutdownOk();
} else if (otherEngine->state() == InferiorRunOk) {
otherEngine->quitDebugger();
} else if (otherEngine->state() == InferiorStopOk) {
otherEngine->quitDebugger();
} else if (otherEngine->state() == EngineRunFailed) {
EDEBUG("... INFERIOR STOPPED, OTHER ENGINE FAILED");
notifyEngineRunFailed();
} else if (otherEngine->state() == InferiorSetupFailed) {
EDEBUG("... INFERIOR STOPPED, OTHER INFERIOR FAILED");
notifyInferiorSetupFailed();
}
break; break;
case EngineShutdownRequested: case EngineShutdownRequested:
break; break;
case EngineShutdownFailed: case EngineShutdownFailed:
qmlEngine()->quitDebugger();
notifyEngineShutdownFailed(); notifyEngineShutdownFailed();
break; break;
case EngineShutdownOk: case EngineShutdownOk: {
if (otherEngine->state() == EngineShutdownOk) qmlEngine()->quitDebugger();
; // Wait for DebuggerFinished. notifyEngineShutdownOk();
else
EDEBUG("... WAITING FOR OTHER ENGINE SHUTDOWN...");
break; break;
}
case DebuggerFinished: case DebuggerFinished:
if (otherEngine->state() == DebuggerFinished)
notifyEngineShutdownOk();
else
EDEBUG("... WAITING FOR OTHER DEBUGGER TO FINISH...");
break; break;
} }
} else {
// QML engine state change
if (newState == InferiorStopOk) {
if (d->m_activeEngine != qmlEngine()) {
showStatusMessage(tr("QML debugger activated"));
d->m_activeEngine = qmlEngine();
}
if (state() == InferiorRunOk)
notifyInferiorSpontaneousStop();
else
notifyInferiorStopOk();
} else if (newState == InferiorRunOk) {
if (d->m_activeEngine == qmlEngine())
notifyInferiorRunOk();
}
}
} }
void QmlCppEngine::handleRemoteSetupDone(int gdbServerPort, int qmlPort) void QmlCppEngine::handleRemoteSetupDone(int gdbServerPort, int qmlPort)

View File

@@ -249,8 +249,10 @@ void QmlEngine::connectionError(QAbstractSocket::SocketError socketError)
if (socketError == QAbstractSocket::RemoteHostClosedError) if (socketError == QAbstractSocket::RemoteHostClosedError)
showMessage(tr("QML Debugger: Remote host closed connection."), StatusBar); showMessage(tr("QML Debugger: Remote host closed connection."), StatusBar);
if (!isSlaveEngine()) { // normal flow for slave engine when gdb exits
notifyInferiorSpontaneousStop(); notifyInferiorSpontaneousStop();
notifyInferiorIll(); notifyInferiorIll();
}
} }
void QmlEngine::serviceConnectionError(const QString &serviceName) void QmlEngine::serviceConnectionError(const QString &serviceName)