Commit acc86aee authored by hjk's avatar hjk

ProjectExplorer: Move re-runnable decision to RunWorkers

A RunControl is re-runnable if all its workers are,
a RunWorker is re-runnable if it's Stopped and unless it
says otherwise.

Also ensure SimpleTargetRunner only reportStop() once
per run and make process error message re-usable.

Change-Id: I73f5fb724d3026ceb81d5e32a3a71b4814b2bca9
Reviewed-by: Christian Stenger's avatarChristian Stenger <christian.stenger@qt.io>
parent 34dad7e3
...@@ -75,7 +75,7 @@ ClangStaticAnalyzerToolRunner::ClangStaticAnalyzerToolRunner(RunControl *runCont ...@@ -75,7 +75,7 @@ ClangStaticAnalyzerToolRunner::ClangStaticAnalyzerToolRunner(RunControl *runCont
setDisplayName("ClangStaticAnalyzerRunner"); setDisplayName("ClangStaticAnalyzerRunner");
runControl->setDisplayName(tr("Clang Static Analyzer")); runControl->setDisplayName(tr("Clang Static Analyzer"));
runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
runControl->setSupportsReRunning(false); setSupportsReRunning(false);
RunConfiguration *runConfiguration = runControl->runConfiguration(); RunConfiguration *runConfiguration = runControl->runConfiguration();
auto tool = ClangStaticAnalyzerTool::instance(); auto tool = ClangStaticAnalyzerTool::instance();
......
...@@ -116,6 +116,7 @@ void DebuggerRunTool::start() ...@@ -116,6 +116,7 @@ void DebuggerRunTool::start()
TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO);
TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME);
setupEngine();
DebuggerEngine *engine = m_engine; DebuggerEngine *engine = m_engine;
QTC_ASSERT(engine, return); QTC_ASSERT(engine, return);
...@@ -493,6 +494,16 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl) ...@@ -493,6 +494,16 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl)
m_isQmlDebugging(qmlDebugging(runControl)) m_isQmlDebugging(qmlDebugging(runControl))
{ {
setDisplayName("DebuggerRunTool"); setDisplayName("DebuggerRunTool");
runControl->setIcon(ProjectExplorer::Icons::DEBUG_START_SMALL_TOOLBAR);
runControl->setPromptToStop([](bool *optionalPrompt) {
return RunControl::showPromptToStopDialog(
DebuggerRunTool::tr("Close Debugging Session"),
DebuggerRunTool::tr("A debugging session is still in progress. "
"Terminating the session in the current"
" state can leave the target in an inconsistent state."
" Would you still like to terminate it?"),
QString(), QString(), optionalPrompt);
});
} }
DebuggerRunTool::DebuggerRunTool(RunControl *runControl, const DebuggerStartParameters &sp, QString *errorMessage) DebuggerRunTool::DebuggerRunTool(RunControl *runControl, const DebuggerStartParameters &sp, QString *errorMessage)
...@@ -514,30 +525,22 @@ void DebuggerRunTool::setStartParameters(const DebuggerStartParameters &sp, QStr ...@@ -514,30 +525,22 @@ void DebuggerRunTool::setStartParameters(const DebuggerStartParameters &sp, QStr
void DebuggerRunTool::setRunParameters(const DebuggerRunParameters &rp, QString *errorMessage) void DebuggerRunTool::setRunParameters(const DebuggerRunParameters &rp, QString *errorMessage)
{ {
Q_UNUSED(errorMessage);
m_runParameters = rp;
}
void DebuggerRunTool::setupEngine()
{
// QML and/or mixed are not prepared for it.
setSupportsReRunning(!(m_runParameters.languages & QmlLanguage));
// FIXME: Disabled due to Android. Make Android device report available ports instead. // FIXME: Disabled due to Android. Make Android device report available ports instead.
// int portsUsed = portsUsedByDebugger(); // int portsUsed = portsUsedByDebugger();
// if (portsUsed > device()->freePorts().count()) { // if (portsUsed > device()->freePorts().count()) {
// if (errorMessage) // reportFailure(tr("Cannot debug: Not enough free ports available."));
// *errorMessage = tr("Cannot debug: Not enough free ports available.");
// return; // return;
// } // }
m_runParameters = rp;
// QML and/or mixed are not prepared for it.
runControl()->setSupportsReRunning(!(rp.languages & QmlLanguage));
runControl()->setIcon(ProjectExplorer::Icons::DEBUG_START_SMALL_TOOLBAR);
runControl()->setPromptToStop([](bool *optionalPrompt) {
return RunControl::showPromptToStopDialog(
DebuggerRunTool::tr("Close Debugging Session"),
DebuggerRunTool::tr("A debugging session is still in progress. "
"Terminating the session in the current"
" state can leave the target in an inconsistent state."
" Would you still like to terminate it?"),
QString(), QString(), optionalPrompt);
});
if (Internal::fixupParameters(m_runParameters, runControl(), m_errors)) { if (Internal::fixupParameters(m_runParameters, runControl(), m_errors)) {
m_engine = createEngine(m_runParameters.cppEngineType, m_engine = createEngine(m_runParameters.cppEngineType,
m_runParameters.masterEngineType, m_runParameters.masterEngineType,
...@@ -545,9 +548,7 @@ void DebuggerRunTool::setRunParameters(const DebuggerRunParameters &rp, QString ...@@ -545,9 +548,7 @@ void DebuggerRunTool::setRunParameters(const DebuggerRunParameters &rp, QString
m_runParameters.useTerminal, m_runParameters.useTerminal,
&m_errors); &m_errors);
if (!m_engine) { if (!m_engine) {
QString msg = m_errors.join('\n'); reportFailure(m_errors.join('\n'));
if (errorMessage)
*errorMessage = msg;
return; return;
} }
......
...@@ -82,11 +82,14 @@ public: ...@@ -82,11 +82,14 @@ public:
int portsUsedByDebugger() const; int portsUsedByDebugger() const;
void appendSolibSearchPath(const QString &str); void appendSolibSearchPath(const QString &str);
signals: signals:
void aboutToNotifyInferiorSetupOk(); void aboutToNotifyInferiorSetupOk();
private: private:
Internal::DebuggerEngine *m_engine = nullptr; // Master engine void setupEngine();
QPointer<Internal::DebuggerEngine> m_engine; // Master engine
Internal::DebuggerRunParameters m_runParameters; Internal::DebuggerRunParameters m_runParameters;
QStringList m_errors; QStringList m_errors;
bool m_isDying = false; bool m_isDying = false;
......
...@@ -263,36 +263,6 @@ QString GdbEngine::failedToStartMessage() ...@@ -263,36 +263,6 @@ QString GdbEngine::failedToStartMessage()
return tr("The gdb process failed to start."); return tr("The gdb process failed to start.");
} }
QString GdbEngine::errorMessage(QProcess::ProcessError error)
{
switch (error) {
case QProcess::FailedToStart:
return failedToStartMessage() + ' ' + tr("Either the "
"invoked program \"%1\" is missing, or you may have insufficient "
"permissions to invoke the program.\n%2")
.arg(runParameters().debugger.executable, m_gdbProc.errorString());
case QProcess::Crashed:
if (isDying())
return tr("The gdb process crashed some time after starting "
"successfully.");
else
return tr("The gdb process was ended forcefully");
case QProcess::Timedout:
return tr("The last waitFor...() function timed out. "
"The state of QProcess is unchanged, and you can try calling "
"waitFor...() again.");
case QProcess::WriteError:
return tr("An error occurred when attempting to write "
"to the gdb process. For example, the process may not be running, "
"or it may have closed its input channel.");
case QProcess::ReadError:
return tr("An error occurred when attempting to read from "
"the gdb process. For example, the process may not be running.");
default:
return tr("An unknown error in the gdb process occurred.");
}
}
#if 0 #if 0
static void dump(const char *first, const char *middle, const QString & to) static void dump(const char *first, const char *middle, const QString & to)
{ {
...@@ -3880,7 +3850,7 @@ void GdbEngine::startGdb(const QStringList &args) ...@@ -3880,7 +3850,7 @@ void GdbEngine::startGdb(const QStringList &args)
if (!QFileInfo(wd).isDir()) if (!QFileInfo(wd).isDir())
msg = failedToStartMessage() + ' ' + tr("The working directory \"%1\" is not usable.").arg(wd); msg = failedToStartMessage() + ' ' + tr("The working directory \"%1\" is not usable.").arg(wd);
else else
msg = errorMessage(QProcess::FailedToStart); msg = RunWorker::userMessageForProcessError(QProcess::FailedToStart, rp.debugger.executable);
handleAdapterStartFailed(msg); handleAdapterStartFailed(msg);
return; return;
} }
...@@ -4064,7 +4034,11 @@ void GdbEngine::reloadDebuggingHelpers() ...@@ -4064,7 +4034,11 @@ void GdbEngine::reloadDebuggingHelpers()
void GdbEngine::handleGdbError(QProcess::ProcessError error) void GdbEngine::handleGdbError(QProcess::ProcessError error)
{ {
const QString msg = errorMessage(error); QString program = runParameters().debugger.executable;
QString msg = RunWorker::userMessageForProcessError(error, program);
QString errorString = m_gdbProc.errorString();
if (!errorString.isEmpty())
msg += '\n' + errorString;
showMessage("HANDLE GDB ERROR: " + msg); showMessage("HANDLE GDB ERROR: " + msg);
// Show a message box for asynchronously reported issues. // Show a message box for asynchronously reported issues.
switch (error) { switch (error) {
......
...@@ -374,7 +374,6 @@ protected: ...@@ -374,7 +374,6 @@ protected:
// //
// Convenience Functions // Convenience Functions
// //
QString errorMessage(QProcess::ProcessError error);
void showExecutionError(const QString &message); void showExecutionError(const QString &message);
QString failedToStartMessage(); QString failedToStartMessage();
......
...@@ -515,7 +515,7 @@ void AppOutputPane::reRunRunControl() ...@@ -515,7 +515,7 @@ void AppOutputPane::reRunRunControl()
handleOldOutput(tab.window); handleOldOutput(tab.window);
tab.window->scrollToBottom(); tab.window->scrollToBottom();
tab.runControl->initiateStart(); tab.runControl->initiateReStart();
} }
void AppOutputPane::attachToRunControl() void AppOutputPane::attachToRunControl()
......
...@@ -615,6 +615,7 @@ public: ...@@ -615,6 +615,7 @@ public:
int startWatchdogTimerId = -1; int startWatchdogTimerId = -1;
int stopWatchdogInterval = 0; // 5000; int stopWatchdogInterval = 0; // 5000;
int stopWatchdogTimerId = -1; int stopWatchdogTimerId = -1;
bool supportsReRunning = true;
}; };
enum class RunControlState enum class RunControlState
...@@ -671,6 +672,7 @@ public: ...@@ -671,6 +672,7 @@ public:
void debugMessage(const QString &msg); void debugMessage(const QString &msg);
void initiateStart(); void initiateStart();
void initiateReStart();
void continueStart(); void continueStart();
void initiateStop(); void initiateStop();
void continueStop(); void continueStop();
...@@ -682,6 +684,7 @@ public: ...@@ -682,6 +684,7 @@ public:
void showError(const QString &msg); void showError(const QString &msg);
static bool isAllowedTransition(RunControlState from, RunControlState to); static bool isAllowedTransition(RunControlState from, RunControlState to);
bool supportsReRunning() const;
RunControl *q; RunControl *q;
QString displayName; QString displayName;
...@@ -699,7 +702,6 @@ public: ...@@ -699,7 +702,6 @@ public:
Utils::ProcessHandle applicationProcessHandle; Utils::ProcessHandle applicationProcessHandle;
RunControlState state = RunControlState::Initialized; RunControlState state = RunControlState::Initialized;
bool supportsReRunning = true;
QList<QPointer<RunWorker>> m_workers; QList<QPointer<RunWorker>> m_workers;
...@@ -751,6 +753,12 @@ void RunControl::initiateStart() ...@@ -751,6 +753,12 @@ void RunControl::initiateStart()
d->initiateStart(); d->initiateStart();
} }
void RunControl::initiateReStart()
{
emit aboutToStart();
d->initiateReStart();
}
void RunControl::initiateStop() void RunControl::initiateStop()
{ {
d->initiateStop(); d->initiateStop();
...@@ -808,6 +816,22 @@ void RunControlPrivate::initiateStart() ...@@ -808,6 +816,22 @@ void RunControlPrivate::initiateStart()
continueStart(); continueStart();
} }
void RunControlPrivate::initiateReStart()
{
checkState(RunControlState::Stopped);
// Re-set worked on re-runs.
for (RunWorker *worker : m_workers) {
if (worker->d->state == RunWorkerState::Done)
worker->d->state = RunWorkerState::Initialized;
}
setState(RunControlState::Starting);
debugMessage("Queue: ReStarting");
continueStart();
}
void RunControlPrivate::continueStart() void RunControlPrivate::continueStart()
{ {
checkState(RunControlState::Starting); checkState(RunControlState::Starting);
...@@ -870,6 +894,7 @@ void RunControlPrivate::continueStop() ...@@ -870,6 +894,7 @@ void RunControlPrivate::continueStop()
{ {
debugMessage("Continue Stopping"); debugMessage("Continue Stopping");
checkState(RunControlState::Stopping); checkState(RunControlState::Stopping);
bool allDone = true;
for (RunWorker *worker : m_workers) { for (RunWorker *worker : m_workers) {
if (worker) { if (worker) {
const QString &workerId = worker->d->id; const QString &workerId = worker->d->id;
...@@ -881,15 +906,18 @@ void RunControlPrivate::continueStop() ...@@ -881,15 +906,18 @@ void RunControlPrivate::continueStop()
break; break;
case RunWorkerState::Stopping: case RunWorkerState::Stopping:
debugMessage(" " + workerId + " was already Stopping. Keeping it that way"); debugMessage(" " + workerId + " was already Stopping. Keeping it that way");
allDone = false;
break; break;
case RunWorkerState::Starting: case RunWorkerState::Starting:
worker->d->state = RunWorkerState::Stopping; worker->d->state = RunWorkerState::Stopping;
debugMessage(" " + workerId + " was Starting, queuing stop"); debugMessage(" " + workerId + " was Starting, queuing stop");
allDone = false;
QTimer::singleShot(0, worker, &RunWorker::initiateStop); QTimer::singleShot(0, worker, &RunWorker::initiateStop);
return; // Sic. return; // Sic.
case RunWorkerState::Running: case RunWorkerState::Running:
debugMessage(" " + workerId + " was Running, queuing stop"); debugMessage(" " + workerId + " was Running, queuing stop");
worker->d->state = RunWorkerState::Stopping; worker->d->state = RunWorkerState::Stopping;
allDone = false;
QTimer::singleShot(0, worker, &RunWorker::initiateStop); QTimer::singleShot(0, worker, &RunWorker::initiateStop);
return; // Sic. return; // Sic.
case RunWorkerState::Done: case RunWorkerState::Done:
...@@ -903,8 +931,10 @@ void RunControlPrivate::continueStop() ...@@ -903,8 +931,10 @@ void RunControlPrivate::continueStop()
debugMessage("Found unknown deleted worker"); debugMessage("Found unknown deleted worker");
} }
} }
debugMessage("All workers stopped. Set runControl to Stopped"); if (allDone) {
setState(RunControlState::Stopped); debugMessage("All workers stopped. Set runControl to Stopped");
setState(RunControlState::Stopped);
}
} }
void RunControlPrivate::onWorkerStarted(RunWorker *worker) void RunControlPrivate::onWorkerStarted(RunWorker *worker)
...@@ -1077,12 +1107,18 @@ void RunControl::setPromptToStop(const std::function<bool (bool *)> &promptToSto ...@@ -1077,12 +1107,18 @@ void RunControl::setPromptToStop(const std::function<bool (bool *)> &promptToSto
bool RunControl::supportsReRunning() const bool RunControl::supportsReRunning() const
{ {
return d->supportsReRunning; return d->supportsReRunning();
} }
void RunControl::setSupportsReRunning(bool reRunningSupported) bool RunControlPrivate::supportsReRunning() const
{ {
d->supportsReRunning = reRunningSupported; for (RunWorker *worker : m_workers) {
if (!worker->d->supportsReRunning)
return false;
if (worker->d->state != RunWorkerState::Done)
return false;
}
return true;
} }
bool RunControl::isRunning() const bool RunControl::isRunning() const
...@@ -1185,7 +1221,6 @@ void RunControlPrivate::setState(RunControlState newState) ...@@ -1185,7 +1221,6 @@ void RunControlPrivate::setState(RunControlState newState)
foreach (auto worker, m_workers) foreach (auto worker, m_workers)
if (worker) if (worker)
worker->onFinished(); worker->onFinished();
//state = RunControlState::Initialized; // Reset for potential re-running.
emit q->finished(); emit q->finished();
break; break;
default: default:
...@@ -1261,6 +1296,7 @@ SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl) ...@@ -1261,6 +1296,7 @@ SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl)
void SimpleTargetRunner::start() void SimpleTargetRunner::start()
{ {
m_stopReported = false;
m_launcher.disconnect(this); m_launcher.disconnect(this);
QString msg = RunControl::tr("Starting %1...").arg(m_runnable.displayName()); QString msg = RunControl::tr("Starting %1...").arg(m_runnable.displayName());
...@@ -1358,14 +1394,22 @@ void SimpleTargetRunner::onProcessFinished(int exitCode, QProcess::ExitStatus st ...@@ -1358,14 +1394,22 @@ void SimpleTargetRunner::onProcessFinished(int exitCode, QProcess::ExitStatus st
else else
msg = tr("%2 exited with code %1").arg(exitCode); msg = tr("%2 exited with code %1").arg(exitCode);
appendMessage(msg.arg(m_runnable.displayName()), Utils::NormalMessageFormat); appendMessage(msg.arg(m_runnable.displayName()), Utils::NormalMessageFormat);
reportStopped(); if (!m_stopReported) {
m_stopReported = true;
reportStopped();
}
} }
void SimpleTargetRunner::onProcessError(QProcess::ProcessError) void SimpleTargetRunner::onProcessError(QProcess::ProcessError error)
{ {
QString msg = tr("%1 finished."); if (error == QProcess::Timedout)
appendMessage(msg.arg(m_runnable.displayName()), Utils::NormalMessageFormat); return; // No actual change on the process side.
reportStopped(); QString msg = userMessageForProcessError(error, m_runnable.displayName());
appendMessage(msg, Utils::NormalMessageFormat);
if (!m_stopReported) {
m_stopReported = true;
reportStopped();
}
} }
void SimpleTargetRunner::setRunnable(const Runnable &runnable) void SimpleTargetRunner::setRunnable(const Runnable &runnable)
...@@ -1519,6 +1563,49 @@ QVariant RunWorker::recordedData(const QString &channel) const ...@@ -1519,6 +1563,49 @@ QVariant RunWorker::recordedData(const QString &channel) const
return d->data[channel]; return d->data[channel];
} }
void RunWorker::setSupportsReRunning(bool reRunningSupported)
{
d->supportsReRunning = reRunningSupported;
}
bool RunWorker::supportsReRunning() const
{
return d->supportsReRunning;
}
QString RunWorker::userMessageForProcessError(QProcess::ProcessError error, const QString &program)
{
QString failedToStart = tr("The process failed to start.");
QString msg = tr("An unknown error in the process occurred.");
switch (error) {
case QProcess::FailedToStart:
msg = failedToStart + ' ' + tr("Either the "
"invoked program \"%1\" is missing, or you may have insufficient "
"permissions to invoke the program.").arg(program);
break;
case QProcess::Crashed:
msg = tr("The process was ended forcefully");
break;
case QProcess::Timedout:
// "The last waitFor...() function timed out. "
// "The state of QProcess is unchanged, and you can try calling "
// "waitFor...() again."
return QString(); // sic!
case QProcess::WriteError:
msg = tr("An error occurred when attempting to write "
"to the process. For example, the process may not be running, "
"or it may have closed its input channel.");
break;
case QProcess::ReadError:
msg = tr("An error occurred when attempting to read from "
"the process. For example, the process may not be running.");
break;
case QProcess::UnknownError:
break;
}
return msg;
}
void RunWorker::start() void RunWorker::start()
{ {
reportStarted(); reportStarted();
......
...@@ -359,6 +359,10 @@ public: ...@@ -359,6 +359,10 @@ public:
void reportStopped(); void reportStopped();
void reportFailure(const QString &msg = QString()); void reportFailure(const QString &msg = QString());
void setSupportsReRunning(bool reRunningSupported);
bool supportsReRunning() const;
static QString userMessageForProcessError(QProcess::ProcessError, const QString &programName);
signals: signals:
void dataReported(int channel, const QVariant &data); void dataReported(int channel, const QVariant &data);
...@@ -393,13 +397,13 @@ public: ...@@ -393,13 +397,13 @@ public:
~RunControl() override; ~RunControl() override;
void initiateStart(); void initiateStart();
void initiateReStart();
void initiateStop(); void initiateStop();
bool promptToStop(bool *optionalPrompt = nullptr) const; bool promptToStop(bool *optionalPrompt = nullptr) const;
void setPromptToStop(const std::function<bool(bool *)> &promptToStop); void setPromptToStop(const std::function<bool(bool *)> &promptToStop);
virtual bool supportsReRunning() const; bool supportsReRunning() const;
void setSupportsReRunning(bool reRunningSupported);
virtual QString displayName() const; virtual QString displayName() const;
void setDisplayName(const QString &displayName); void setDisplayName(const QString &displayName);
...@@ -512,6 +516,7 @@ private: ...@@ -512,6 +516,7 @@ private:
ApplicationLauncher m_launcher; ApplicationLauncher m_launcher;
Runnable m_runnable; Runnable m_runnable;
bool m_stopReported = false;
}; };
} // namespace ProjectExplorer } // namespace ProjectExplorer
...@@ -88,7 +88,7 @@ QmlProfilerRunner::QmlProfilerRunner(RunControl *runControl) ...@@ -88,7 +88,7 @@ QmlProfilerRunner::QmlProfilerRunner(RunControl *runControl)
{ {
setDisplayName("QmlProfilerRunner"); setDisplayName("QmlProfilerRunner");
runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
runControl->setSupportsReRunning(false); setSupportsReRunning(false);
// Only wait 4 seconds for the 'Waiting for connection' on application output, then just try to connect // Only wait 4 seconds for the 'Waiting for connection' on application output, then just try to connect
// (application output might be redirected / blocked) // (application output might be redirected / blocked)
......
...@@ -55,7 +55,7 @@ ValgrindToolRunner::ValgrindToolRunner(RunControl *runControl) ...@@ -55,7 +55,7 @@ ValgrindToolRunner::ValgrindToolRunner(RunControl *runControl)
: RunWorker(runControl) : RunWorker(runControl)
{ {
runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
runControl->setSupportsReRunning(false); setSupportsReRunning(false);
if (IRunConfigurationAspect *aspect = runControl->runConfiguration()->extraAspect(ANALYZER_VALGRIND_SETTINGS)) if (IRunConfigurationAspect *aspect = runControl->runConfiguration()->extraAspect(ANALYZER_VALGRIND_SETTINGS))
m_settings = qobject_cast<ValgrindBaseSettings *>(aspect->currentSettings()); m_settings = qobject_cast<ValgrindBaseSettings *>(aspect->currentSettings());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment