diff --git a/src/libs/utils/port.h b/src/libs/utils/port.h index c05c8b2d388..e668c46265b 100644 --- a/src/libs/utils/port.h +++ b/src/libs/utils/port.h @@ -27,8 +27,11 @@ #include "utils_global.h" #include "qtcassert.h" -#include + #include +#include + +#include namespace Utils { @@ -50,6 +53,8 @@ public: quint16 number() const { QTC_ASSERT(isValid(), return 0); return quint16(m_port); } bool isValid() const { return m_port != -1; } + QString toString() const { return QString::number(m_port); } + private: int m_port; }; diff --git a/src/plugins/android/androidanalyzesupport.cpp b/src/plugins/android/androidanalyzesupport.cpp index bf5579c867c..4ee0463489b 100644 --- a/src/plugins/android/androidanalyzesupport.cpp +++ b/src/plugins/android/androidanalyzesupport.cpp @@ -48,7 +48,8 @@ namespace Internal { RunControl *AndroidAnalyzeSupport::createAnalyzeRunControl(RunConfiguration *runConfig, Core::Id runMode) { - RunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, runMode); + auto runControl = new RunControl(runConfig, runMode); + runControl->createWorker(runMode); QTC_ASSERT(runControl, return 0); AnalyzerConnection connection; if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { @@ -64,7 +65,7 @@ RunControl *AndroidAnalyzeSupport::createAnalyzeRunControl(RunConfiguration *run } AndroidAnalyzeSupport::AndroidAnalyzeSupport(RunControl *runControl) - : ToolRunner(runControl) + : RunWorker(runControl) { auto runner = new AndroidRunner(this, runControl->runConfiguration(), runControl->runMode()); diff --git a/src/plugins/android/androidanalyzesupport.h b/src/plugins/android/androidanalyzesupport.h index 887796153d7..6c96fc658a7 100644 --- a/src/plugins/android/androidanalyzesupport.h +++ b/src/plugins/android/androidanalyzesupport.h @@ -34,7 +34,7 @@ namespace Android { namespace Internal { -class AndroidAnalyzeSupport : public ProjectExplorer::ToolRunner +class AndroidAnalyzeSupport : public ProjectExplorer::RunWorker { Q_OBJECT diff --git a/src/plugins/android/androidrunnable.h b/src/plugins/android/androidrunnable.h index c6ff742112b..0c1a8942504 100644 --- a/src/plugins/android/androidrunnable.h +++ b/src/plugins/android/androidrunnable.h @@ -40,6 +40,7 @@ struct ANDROID_EXPORT AndroidRunnable QVector afterFinishADBCommands; QString deviceSerialNumber; + QString displayName() const { return packageName; } static void *staticTypeId; }; diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp index 37721ec7728..43fdf32bc0e 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp @@ -71,8 +71,9 @@ namespace Internal { ClangStaticAnalyzerToolRunner::ClangStaticAnalyzerToolRunner(RunControl *runControl, QString *errorMessage) - : ToolRunner(runControl) + : RunWorker(runControl) { + setDisplayName("ClangStaticAnalyzerRunner"); runControl->setDisplayName(tr("Clang Static Analyzer")); runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); runControl->setSupportsReRunning(false); @@ -585,7 +586,7 @@ void ClangStaticAnalyzerToolRunner::start() return; } - reportSuccess(); + reportStarted(); while (m_runners.size() < parallelRuns && !m_unitsToProcess.isEmpty()) analyzeNextFile(); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h index 28d76004938..3c6b4267d7f 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h @@ -47,7 +47,7 @@ struct AnalyzeUnit { }; typedef QList AnalyzeUnits; -class ClangStaticAnalyzerToolRunner : public ProjectExplorer::ToolRunner +class ClangStaticAnalyzerToolRunner : public ProjectExplorer::RunWorker { Q_OBJECT diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp index e1e7c2adefb..c8f1f6c8ba2 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp @@ -145,7 +145,7 @@ ClangStaticAnalyzerTool::ClangStaticAnalyzerTool() {{ClangStaticAnalyzerDockId, m_diagnosticView, {}, Perspective::SplitVertical}} )); - Debugger::registerAction(Constants::CLANGSTATICANALYZER_RUN_MODE, {}); + //Debugger::registerAction(Constants::CLANGSTATICANALYZER_RUN_MODE, {}); action = new QAction(tr("Clang Static Analyzer"), this); action->setToolTip(toolTip); menu->addAction(ActionManager::registerAction(action, "ClangStaticAnalyzer.Action"), diff --git a/src/plugins/debugger/analyzer/analyzermanager.h b/src/plugins/debugger/analyzer/analyzermanager.h index 3558a796463..9a3dedd9d99 100644 --- a/src/plugins/debugger/analyzer/analyzermanager.h +++ b/src/plugins/debugger/analyzer/analyzermanager.h @@ -59,16 +59,12 @@ enum ToolMode { //AnyMode = DebugMode | ProfileMode | ReleaseMode }; -using RunControlCreator = std::function; - // FIXME: Merge with something sensible. DEBUGGER_EXPORT bool wantRunTool(ToolMode toolMode, const QString &toolName); DEBUGGER_EXPORT void showCannotStartDialog(const QString &toolName); DEBUGGER_EXPORT ProjectExplorer::RunConfiguration *startupRunConfiguration(); // Register a tool for a given start mode. -DEBUGGER_EXPORT void registerAction(Core::Id runMode, const RunControlCreator &runControlCreator); DEBUGGER_EXPORT void registerPerspective(const QByteArray &perspectiveId, const Utils::Perspective *perspective); DEBUGGER_EXPORT void registerToolbar(const QByteArray &perspectiveId, const Utils::ToolbarDescription &desc); @@ -85,7 +81,4 @@ DEBUGGER_EXPORT void showPermanentStatusMessage(const QString &message); DEBUGGER_EXPORT QAction *createStartAction(); DEBUGGER_EXPORT QAction *createStopAction(); -DEBUGGER_EXPORT ProjectExplorer::RunControl *createAnalyzerRunControl( - ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); - } // namespace Debugger diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index d99a2cdec08..31a3997dd59 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -561,7 +561,7 @@ void DebuggerEngine::setRunTool(DebuggerRunTool *runTool) d->m_runTool = runTool; } -void DebuggerEngine::prepare() +void DebuggerEngine::start() { QTC_ASSERT(d->m_runTool, notifyEngineSetupFailed(); return); @@ -602,25 +602,7 @@ void DebuggerEngine::prepare() } d->queueSetupEngine(); -} - -void DebuggerEngine::start() -{ - Internal::runControlStarted(this); - - // We might get a synchronous startFailed() notification on Windows, - // when launching the process fails. Emit a proper finished() sequence. - //runControl()->reportApplicationStart(); - - showMessage("QUEUE: SETUP INFERIOR"); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state()); -// if (isMasterEngine()) - d->queueSetupInferior(); -} - -void DebuggerEngine::startDebugger() -{ - d->queueRunEngine(); } void DebuggerEngine::resetLocation() @@ -822,7 +804,9 @@ void DebuggerEngine::notifyEngineSetupOk() QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state()); setState(EngineSetupOk); - runTool()->reportSuccess(); + + Internal::runControlStarted(this); + d->queueSetupInferior(); } void DebuggerEngine::setupSlaveInferior() @@ -1313,6 +1297,11 @@ void DebuggerEngine::setState(DebuggerState state, bool forced) DebuggerToolTipManager::registerEngine(this); } + if (state == InferiorUnrunnable || state == InferiorRunOk) { + if (isMasterEngine() && runTool()) + runTool()->reportStarted(); + } + if (state == DebuggerFinished) { // Give up ownership on claimed breakpoints. foreach (Breakpoint bp, breakHandler()->engineBreakpoints(this)) diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 75a1174af9e..aa927b89dd2 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -202,11 +202,8 @@ public: virtual void setRunTool(DebuggerRunTool *runTool); DebuggerRunTool *runTool() const; - void prepare(); void start(); - void startDebugger(); - enum { // Remove need to qualify each use. NeedsTemporaryStop = DebuggerCommand::NeedsTemporaryStop, diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index c712f8246bd..5af6473faf9 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -973,7 +973,6 @@ public: QPointer m_modeWindow; QPointer m_mode; - QHash m_runControlCreators; ActionContainer *m_menu = 0; // DockWidgetEventFilter m_resizeEventFilter; @@ -3527,11 +3526,6 @@ bool wantRunTool(ToolMode toolMode, const QString &toolName) return true; } -void registerAction(Id runMode, const RunControlCreator &runControlCreator) -{ - dd->m_runControlCreators.insert(runMode, runControlCreator); -} - void registerToolbar(const QByteArray &perspectiveId, const ToolbarDescription &desc) { auto toolbar = new QWidget; @@ -3605,14 +3599,6 @@ void showPermanentStatusMessage(const QString &message) dd->m_mainWindow->showStatusMessage(message, -1); } -RunControl *createAnalyzerRunControl(RunConfiguration *runConfiguration, Id runMode) -{ - RunControlCreator rcc = dd->m_runControlCreators.value(runMode); - if (rcc) - return rcc(runConfiguration, runMode); - return nullptr; -} - namespace Internal { static bool s_testRun = false; diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 9e62606f364..2e5f42db98c 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -109,19 +109,15 @@ static QLatin1String engineTypeName(DebuggerEngineType et) return QLatin1String("No engine"); } -void DebuggerRunTool::prepare() +void DebuggerRunTool::start() { Debugger::Internal::saveModeToRestore(); Debugger::selectPerspective(Debugger::Constants::CppPerspectiveId); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME); - m_engine->prepare(); -} - -void DebuggerRunTool::start() -{ DebuggerEngine *engine = m_engine; + QTC_ASSERT(engine, return); const DebuggerRunParameters &rp = engine->runParameters(); // User canceled input dialog asking for executable when working on library project. @@ -177,11 +173,6 @@ void DebuggerRunTool::notifyEngineRemoteSetupFinished(const RemoteSetupResult &r m_engine->notifyEngineRemoteSetupFinished(result); } -void DebuggerRunTool::setRemoteParameters(const RemoteSetupResult &result) -{ - m_engine->setRemoteParameters(result); -} - void DebuggerRunTool::stop() { m_engine->quitDebugger(); @@ -199,7 +190,7 @@ void DebuggerRunTool::onTargetFailure() void DebuggerRunTool::debuggingFinished() { - runControl()->reportApplicationStop(); + reportStopped(); } DebuggerStartParameters &DebuggerRunTool::startParameters() @@ -495,10 +486,11 @@ static DebuggerRunConfigurationAspect *debuggerAspect(const RunControl *runContr /// DebuggerRunTool DebuggerRunTool::DebuggerRunTool(RunControl *runControl) - : ToolRunner(runControl), + : RunWorker(runControl), m_isCppDebugging(debuggerAspect(runControl)->useCppDebugger()), m_isQmlDebugging(debuggerAspect(runControl)->useQmlDebugger()) { + setDisplayName("DebuggerRunTool"); } DebuggerRunTool::DebuggerRunTool(RunControl *runControl, const DebuggerStartParameters &sp, QString *errorMessage) @@ -577,7 +569,7 @@ DebuggerRunTool::~DebuggerRunTool() void DebuggerRunTool::onFinished() { - appendMessage(tr("Debugging has finished") + '\n', NormalMessageFormat); + appendMessage(tr("Debugging has finished"), NormalMessageFormat); runControlFinished(m_engine); } @@ -619,8 +611,9 @@ public: QTC_ASSERT(runConfig, return 0); QTC_ASSERT(mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain, return 0); + DebuggerStartParameters sp; auto runControl = new RunControl(runConfig, mode); - (void) new DebuggerRunTool(runControl, DebuggerStartParameters(), errorMessage); + (void) new DebuggerRunTool(runControl, sp, errorMessage); return runControl; } @@ -690,10 +683,109 @@ RunControl *createAndScheduleRun(const DebuggerRunParameters &rp, Kit *kit) QTC_ASSERT(runConfig, return nullptr); auto runControl = new RunControl(runConfig, DebugRunMode); (void) new DebuggerRunTool(runControl, rp); - QTC_ASSERT(runControl, return nullptr); ProjectExplorerPlugin::startRunControl(runControl); return runControl; } } // Internal + +// GdbServerPortGatherer + +GdbServerPortsGatherer::GdbServerPortsGatherer(RunControl *runControl) + : RunWorker(runControl) +{ +} + +GdbServerPortsGatherer::~GdbServerPortsGatherer() +{ +} + +void GdbServerPortsGatherer::start() +{ + appendMessage(tr("Checking available ports..."), NormalMessageFormat); + connect(&m_portsGatherer, &DeviceUsedPortsGatherer::error, this, [this](const QString &msg) { + reportFailure(msg); + }); + connect(&m_portsGatherer, &DeviceUsedPortsGatherer::portListReady, this, [this] { + Utils::PortList portList = device()->freePorts(); + appendMessage(tr("Found %1 free ports").arg(portList.count()), NormalMessageFormat); + if (m_useGdbServer) { + m_gdbServerPort = m_portsGatherer.getNextFreePort(&portList); + if (!m_gdbServerPort.isValid()) { + reportFailure(tr("Not enough free ports on device for C++ debugging.")); + return; + } + } + if (m_useQmlServer) { + m_qmlServerPort = m_portsGatherer.getNextFreePort(&portList); + if (!m_qmlServerPort.isValid()) { + reportFailure(tr("Not enough free ports on device for QML debugging.")); + return; + } + } + reportStarted(); + }); + m_portsGatherer.start(device()); +} + + +// GdbServerRunner + +GdbServerRunner::GdbServerRunner(RunControl *runControl) + : RunWorker(runControl) +{ + setDisplayName("GdbServerRunner"); +} + +GdbServerRunner::~GdbServerRunner() +{ +} + +void GdbServerRunner::start() +{ + auto portsGatherer = runControl()->worker(); + QTC_ASSERT(portsGatherer, reportFailure(); return); + + StandardRunnable r = runnable().as(); + QStringList args = QtcProcess::splitArgs(r.commandLineArguments, OsTypeLinux); + QString command; + + const bool isQmlDebugging = portsGatherer->useQmlServer(); + const bool isCppDebugging = portsGatherer->useGdbServer(); + + if (isQmlDebugging) { + args.prepend(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices, + portsGatherer->qmlServerPort())); + } + + if (isQmlDebugging && !isCppDebugging) { + command = r.executable; + } else { + command = device()->debugServerPath(); + if (command.isEmpty()) + command = "gdbserver"; + args.clear(); + args.append(QString("--multi")); + args.append(QString(":%1").arg(portsGatherer->gdbServerPort().number())); + } + r.executable = command; + r.commandLineArguments = QtcProcess::joinArgs(args, OsTypeLinux); + + connect(&m_gdbServer, &ApplicationLauncher::error, this, [this] { + reportFailure(tr("GDBserver start failed")); + }); + connect(&m_gdbServer, &ApplicationLauncher::remoteProcessStarted, this, [this] { + appendMessage(tr("GDBserver started") + '\n', NormalMessageFormat); + reportStarted(); + }); + + appendMessage(tr("Starting GDBserver...") + '\n', NormalMessageFormat); + m_gdbServer.start(r, device()); +} + +void GdbServerRunner::onFinished() +{ + m_gdbServer.stop(); +} + } // namespace Debugger diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index fef388cc91b..29c5a7e545e 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -30,13 +30,14 @@ #include "debuggerengine.h" #include +#include namespace Debugger { class RemoteSetupResult; class DebuggerStartParameters; -class DEBUGGER_EXPORT DebuggerRunTool : public ProjectExplorer::ToolRunner +class DEBUGGER_EXPORT DebuggerRunTool : public ProjectExplorer::RunWorker { Q_OBJECT @@ -60,16 +61,14 @@ public: void showMessage(const QString &msg, int channel = LogDebug, int timeout = -1); - void prepare() override; void start() override; void stop() override; - void onTargetFailure() override; void onFinished() override; void startFailed(); + void onTargetFailure(); void notifyEngineRemoteServerRunning(const QByteArray &msg, int pid); void notifyEngineRemoteSetupFinished(const RemoteSetupResult &result); - void setRemoteParameters(const RemoteSetupResult &result); void notifyInferiorIll(); Q_SLOT void notifyInferiorExited(); void quitDebugger(); @@ -97,4 +96,48 @@ private: const bool m_isQmlDebugging; }; +class DEBUGGER_EXPORT GdbServerPortsGatherer : public ProjectExplorer::RunWorker +{ + Q_OBJECT + +public: + explicit GdbServerPortsGatherer(ProjectExplorer::RunControl *runControl); + ~GdbServerPortsGatherer(); + + void setUseGdbServer(bool useIt) { m_useGdbServer = useIt; } + bool useGdbServer() const { return m_useGdbServer; } + Utils::Port gdbServerPort() const { return m_gdbServerPort; } + + void setUseQmlServer(bool useIt) { m_useQmlServer = useIt; } + bool useQmlServer() const { return m_useQmlServer; } + Utils::Port qmlServerPort() const { return m_qmlServerPort; } + +private: + void start(); + + ProjectExplorer::DeviceUsedPortsGatherer m_portsGatherer; + bool m_useGdbServer = false; + bool m_useQmlServer = false; + Utils::Port m_gdbServerPort; + Utils::Port m_qmlServerPort; +}; + +class DEBUGGER_EXPORT GdbServerRunner : public ProjectExplorer::RunWorker +{ + Q_OBJECT + +public: + explicit GdbServerRunner(ProjectExplorer::RunControl *runControl); + ~GdbServerRunner(); + +private: + void start() override; + void onFinished() override; + + ProjectExplorer::ApplicationLauncher m_gdbServer; +}; + +extern DEBUGGER_EXPORT const char GdbServerRunnerWorkerId[]; +extern DEBUGGER_EXPORT const char GdbServerPortGathererWorkerId[]; + } // namespace Debugger diff --git a/src/plugins/ios/iosanalyzesupport.cpp b/src/plugins/ios/iosanalyzesupport.cpp index 5bdb9a2da77..795da9d1aa9 100644 --- a/src/plugins/ios/iosanalyzesupport.cpp +++ b/src/plugins/ios/iosanalyzesupport.cpp @@ -32,7 +32,7 @@ namespace Ios { namespace Internal { IosAnalyzeSupport::IosAnalyzeSupport(RunControl *runControl, bool cppDebug, bool qmlDebug) - : ToolRunner(runControl), + : RunWorker(runControl), m_runner(new IosRunner(this, runControl, cppDebug, qmlDebug ? QmlDebug::QmlProfilerServices : QmlDebug::NoQmlDebugServices)) { diff --git a/src/plugins/ios/iosanalyzesupport.h b/src/plugins/ios/iosanalyzesupport.h index 6c3677d1a75..2b621034ea3 100644 --- a/src/plugins/ios/iosanalyzesupport.h +++ b/src/plugins/ios/iosanalyzesupport.h @@ -34,7 +34,7 @@ namespace Internal { class IosRunner; -class IosAnalyzeSupport : public ProjectExplorer::ToolRunner +class IosAnalyzeSupport : public ProjectExplorer::RunWorker { Q_OBJECT diff --git a/src/plugins/ios/iosrunfactories.cpp b/src/plugins/ios/iosrunfactories.cpp index b331fdb9f46..5571258d636 100644 --- a/src/plugins/ios/iosrunfactories.cpp +++ b/src/plugins/ios/iosrunfactories.cpp @@ -184,11 +184,8 @@ RunControl *IosRunControlFactory::create(RunConfiguration *runConfig, if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE) res = new Ios::Internal::IosRunControl(rc); else if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - RunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, mode); - QTC_ASSERT(runControl, return 0); - IDevice::ConstPtr device = DeviceKitInformation::device(target->kit()); - if (device.isNull()) - return 0; + auto runControl = new RunControl(runConfig, mode); + runControl->createWorker(mode); auto iosRunConfig = qobject_cast(runConfig); StandardRunnable runnable; runnable.executable = iosRunConfig->localExecutable().toUserOutput(); diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index 3757a0e7b7c..ce5511e9101 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -525,11 +525,16 @@ void AppOutputPane::attachToRunControl() void AppOutputPane::stopRunControl() { const int index = currentIndex(); - QTC_ASSERT(index != -1 && m_runControlTabs.at(index).runControl->isRunning(), return); - + QTC_ASSERT(index != -1, return); RunControl *rc = m_runControlTabs.at(index).runControl; + QTC_ASSERT(rc, return); + if (rc->isRunning() && optionallyPromptToStop(rc)) rc->initiateStop(); + else if (rc->isStarting()) { + QTC_CHECK(false); + rc->initiateStop(); + } if (debug) qDebug() << "OutputPane::stopRunControl " << rc; diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp index 60f4a39ca7b..c5396677e8b 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp @@ -190,4 +190,40 @@ void DeviceUsedPortsGatherer::handleRemoteStdErr() d->remoteStderr += d->process->readAllStandardError(); } +// PortGatherer + +PortsGatherer::PortsGatherer(RunControl *runControl) + : RunWorker(runControl) +{ + setDisplayName("PortGatherer"); +} + +PortsGatherer::~PortsGatherer() +{ +} + +void PortsGatherer::start() +{ + appendMessage(tr("Checking available ports...") + '\n', NormalMessageFormat); + connect(&m_portsGatherer, &DeviceUsedPortsGatherer::error, this, [this](const QString &msg) { + reportFailure(msg); + }); + connect(&m_portsGatherer, &DeviceUsedPortsGatherer::portListReady, this, [this] { + m_portList = device()->freePorts(); + appendMessage(tr("Found %1 free ports").arg(m_portList.count()) + '\n', NormalMessageFormat); + reportStarted(); + }); + m_portsGatherer.start(device()); +} + +Port PortsGatherer::findPort() +{ + return m_portsGatherer.getNextFreePort(&m_portList); +} + +void PortsGatherer::stop() +{ + m_portsGatherer.stop(); +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h index e326557469c..c298b6fbd08 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h @@ -27,10 +27,9 @@ #include "idevice.h" -namespace Utils { -class Port; -class PortList; -} // namespace Utils +#include + +#include namespace ProjectExplorer { namespace Internal { class DeviceUsedPortsGathererPrivate; } @@ -64,4 +63,23 @@ private: Internal::DeviceUsedPortsGathererPrivate * const d; }; +class PROJECTEXPLORER_EXPORT PortsGatherer : public RunWorker +{ + Q_OBJECT + +public: + explicit PortsGatherer(RunControl *runControl); + ~PortsGatherer() override; + + Utils::Port findPort(); + +protected: + void start() override; + void stop() override; + +private: + DeviceUsedPortsGatherer m_portsGatherer; + Utils::PortList m_portList; +}; + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index a48962c6740..a93a0298213 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -35,6 +35,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QWidget; QT_END_NAMESPACE @@ -54,6 +56,8 @@ class Connection; class DeviceProcess; class DeviceProcessList; class Kit; +class RunControl; +class RunWorker; namespace Internal { class IDevicePrivate; } @@ -162,6 +166,8 @@ public: virtual DeviceProcessSignalOperation::Ptr signalOperation() const = 0; virtual DeviceEnvironmentFetcher::Ptr environmentFetcher() const; + virtual std::function workerCreator(Core::Id) const { return {}; } + enum DeviceState { DeviceReadyToUse, DeviceConnected, DeviceDisconnected, DeviceStateUnknown }; DeviceState deviceState() const; void setDeviceState(const DeviceState state); diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index a7d75c38e92..219cc5baff4 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -48,6 +48,8 @@ #include #include #include +#include +#include #ifdef Q_OS_OSX #include @@ -60,7 +62,9 @@ using namespace Utils; using namespace ProjectExplorer::Internal; -const bool debugStates = false; +namespace { +Q_LOGGING_CATEGORY(statesLog, "qtc.projectmanager.states") +} namespace ProjectExplorer { @@ -506,6 +510,70 @@ IRunConfigurationAspect *IRunControlFactory::createRunConfigurationAspect(RunCon namespace Internal { +enum class RunWorkerState +{ + Initialized, Starting, Running, Stopping, Done, Failed +}; + +//static QString stateName(RunWorkerState s) +//{ +//# define SN(x) case x: return QLatin1String(#x); +// switch (s) { +// SN(RunWorkerState::Initialized) +// SN(RunWorkerState::Starting) +// SN(RunWorkerState::Running) +// SN(RunWorkerState::Stopping) +// SN(RunWorkerState::Done) +// SN(RunWorkerState::Failed) +// } +// return QLatin1String(""); +//# undef SN +//} + +class RunWorkerPrivate : public QObject +{ +public: + RunWorkerPrivate(RunWorker *runWorker, RunControl *runControl); + + bool canStart() const; + void timerEvent(QTimerEvent *ev) override; + + RunWorker *q; + RunWorkerState state = RunWorkerState::Initialized; + RunControl *runControl; + QList dependencies; + QString displayName; + + QVariantMap data; + int startWatchdogInterval = 0; + int startWatchdogTimerId = -1; + int stopWatchdogInterval = 0; // 5000; + int stopWatchdogTimerId = -1; +}; + +enum class RunControlState +{ + Initialized, // Default value after creation. + Starting, // Actual process/tool starts. + Running, // All good and running. + Stopping, // initiateStop() was called, stop application/tool + Stopped, // all good, but stopped. Can possibly be re-started +}; + +static QString stateName(RunControlState s) +{ +# define SN(x) case x: return QLatin1String(#x); + switch (s) { + SN(RunControlState::Initialized) + SN(RunControlState::Starting) + SN(RunControlState::Running) + SN(RunControlState::Stopping) + SN(RunControlState::Stopped) + } + return QLatin1String(""); +# undef SN +} + class RunControlPrivate : public QObject { public: @@ -524,63 +592,30 @@ public: ~RunControlPrivate() { - QTC_CHECK(state == State::Stopped || state == State::Initialized); - delete targetRunner; - delete toolRunner; + QTC_CHECK(state == RunControlState::Stopped || state == RunControlState::Initialized); + qDeleteAll(m_workers); delete outputFormatter; } - enum class State { - Initialized, // Default value after creation. - TargetPreparing, // initiateStart() was called, target boots up, connects, etc - ToolPreparing, // Target is acessible, tool boots - TargetStarting, // Late corrections on the target side after tool is available. - ToolStarting, // Actual process/tool starts. - Running, // All good and running. - ToolStopping, // initiateStop() was called, stop application/tool - TargetStopping, // Potential clean up on target, set idle state, etc. - Stopped, // all good, but stopped. Can possibly be re-started - }; - Q_ENUM(State) + Q_ENUM(RunControlState) - void checkState(State expectedState); - void setState(State state); + void checkState(RunControlState expectedState); + void setState(RunControlState state); void debugMessage(const QString &msg); - QString stateName(State s) const; void initiateStart(); - - void onTargetPrepared(); - void onTargetPrepareFailed(const QString &msg); - - void onToolPrepared(); - void onToolPrepareFailed(const QString &msg); - - void onTargetStarted(); - void onTargetStartFailed(const QString &msg); - - void onToolStarted(); - void onToolStartFailed(const QString &msg); - + void continueStart(); void initiateStop(); - void onToolStopped(); - void onToolStopFailed(const QString &msg); + void continueStop(); - void onTargetStopped(); - void onTargetStopFailed(const QString &msg); - - void onToolFailed(const QString &msg); - void onToolSuccess(); - - void onTargetFailed(const QString &msg); - void onTargetSuccess(); - - void handleFailure(); + void onWorkerStarted(RunWorker *worker); + void onWorkerStopped(RunWorker *worker); + void onWorkerFailed(RunWorker *worker, const QString &msg); void showError(const QString &msg); - static bool isAllowedTransition(State from, State to); + static bool isAllowedTransition(RunControlState from, RunControlState to); RunControl *q; QString displayName; @@ -591,17 +626,17 @@ public: Utils::Icon icon; const QPointer runConfiguration; // Not owned. QPointer project; // Not owned. - QPointer targetRunner; // Owned. QPointer as "extra safety" for now. - QPointer toolRunner; // Owned. QPointer as "extra safety" for now. Utils::OutputFormatter *outputFormatter = nullptr; std::function promptToStop; // A handle to the actual application process. Utils::ProcessHandle applicationProcessHandle; - State state = State::Initialized; + RunControlState state = RunControlState::Initialized; bool supportsReRunning = true; + QList> m_workers; + #ifdef Q_OS_OSX // This is used to bring apps in the foreground on Mac int foregroundCount; @@ -615,8 +650,6 @@ using namespace Internal; RunControl::RunControl(RunConfiguration *runConfiguration, Core::Id mode) : d(new RunControlPrivate(this, runConfiguration, mode)) { - (void) new TargetRunner(this); - (void) new ToolRunner(this); #ifdef WITH_JOURNALD JournaldWatcher::instance()->subscribe(this, [this](const JournaldWatcher::LogEntry &entry) { if (entry.value("_MACHINE_ID") != JournaldWatcher::instance()->machineId()) @@ -667,204 +700,178 @@ void RunControl::stop() d->initiateStop(); } +using WorkerCreators = QHash; + +static WorkerCreators &theWorkerCreators() +{ + static WorkerCreators creators; + return creators; +} + +void RunControl::registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator) +{ + theWorkerCreators().insert(id, workerCreator); + auto keys = theWorkerCreators().keys(); + Q_UNUSED(keys); +} + +QList > RunControl::workers() const +{ + return d->m_workers; +} + +RunWorker *RunControl::createWorker(Core::Id id) +{ + auto keys = theWorkerCreators().keys(); + Q_UNUSED(keys); + RunWorkerCreator creator = theWorkerCreators().value(id); + if (creator) + return creator(this); + creator = device()->workerCreator(id); + if (creator) + return creator(this); + return nullptr; +} + void RunControlPrivate::initiateStart() { - checkState(State::Initialized); - setState(State::TargetPreparing); - debugMessage("Queue: Prepare target runner"); - QTimer::singleShot(0, targetRunner, [this](){ targetRunner->prepare(); }); + checkState(RunControlState::Initialized); + setState(RunControlState::Starting); + debugMessage("Queue: Starting"); + + continueStart(); } -void RunControlPrivate::onTargetPrepared() +void RunControlPrivate::continueStart() { - checkState(State::TargetPreparing); - setState(State::ToolPreparing); - debugMessage("Queue: Prepare tool runner"); - QTimer::singleShot(0, toolRunner, [this](){ toolRunner->prepare(); }); -} - -void RunControlPrivate::onTargetPrepareFailed(const QString &msg) -{ - checkState(State::TargetPreparing); - toolRunner->onTargetFailure(); - showError(msg); - setState(State::Stopped); -} - -void RunControlPrivate::onToolPrepared() -{ - checkState(State::ToolPreparing); - setState(State::TargetStarting); - debugMessage("Queue: Start target runner"); - QTimer::singleShot(0, targetRunner, [this](){ targetRunner->start(); }); -} - -void RunControlPrivate::onToolPrepareFailed(const QString &msg) -{ - checkState(State::ToolPreparing); - targetRunner->onToolFailure(); - showError(msg); - setState(State::Stopped); -} - -void RunControlPrivate::onTargetStarted() -{ - checkState(State::TargetStarting); - setState(State::ToolStarting); - debugMessage("Queue: Start tool runner"); - QTimer::singleShot(0, toolRunner, [this](){ toolRunner->start(); }); -} - -void RunControlPrivate::onTargetStartFailed(const QString &msg) -{ - checkState(State::TargetStarting); - toolRunner->onTargetFailure(); - showError(msg); - setState(State::Stopped); -} - -void RunControlPrivate::onToolStarted() -{ - checkState(State::ToolStarting); - setState(State::Running); -} - -void RunControlPrivate::onToolStartFailed(const QString &msg) -{ - checkState(State::ToolStarting); - targetRunner->onToolFailure(); - showError(msg); - setState(State::Stopped); + checkState(RunControlState::Starting); + bool allDone = true; + debugMessage("Looking for next worker"); + for (RunWorker *worker : m_workers) { + if (worker) { + debugMessage(" Examining worker " + worker->displayName()); + switch (worker->d->state) { + case RunWorkerState::Initialized: + debugMessage(" " + worker->displayName() + " is not done yet."); + if (worker->d->canStart()) { + debugMessage("Starting " + worker->displayName()); + worker->d->state = RunWorkerState::Starting; + QTimer::singleShot(0, worker, &RunWorker::initiateStart); + return; + } + allDone = false; + debugMessage(" " + worker->displayName() + " cannot start."); + break; + case RunWorkerState::Starting: + debugMessage(" " + worker->displayName() + " currently starting"); + allDone = false; + break; + case RunWorkerState::Running: + debugMessage(" " + worker->displayName() + " currently running"); + break; + case RunWorkerState::Stopping: + debugMessage(" " + worker->displayName() + " currently stopping"); + continue; + case RunWorkerState::Failed: + // Should not happen. + debugMessage(" " + worker->displayName() + " failed before"); + QTC_CHECK(false); + //setState(RunControlState::Stopped); + break; + case RunWorkerState::Done: + debugMessage(" " + worker->displayName() + " was done before"); + break; + } + } else { + debugMessage("Found unknown deleted worker while starting"); + } + } + if (allDone) + setState(RunControlState::Running); } void RunControlPrivate::initiateStop() { - checkState(State::Running); - setState(State::ToolStopping); - debugMessage("Queue: Stop tool runner"); - QTimer::singleShot(0, toolRunner, [this](){ toolRunner->stop(); }); + checkState(RunControlState::Running); + setState(RunControlState::Stopping); + debugMessage("Queue: Stopping"); + + continueStop(); } -void RunControlPrivate::onToolStopped() +void RunControlPrivate::continueStop() { - toolRunner->onStop(); - debugMessage("Tool stopped"); - checkState(State::ToolStopping); - setState(State::TargetStopping); - debugMessage("Queue: Stop target runner"); - QTimer::singleShot(0, targetRunner, [this](){ targetRunner->stop(); }); + debugMessage("Continue Stopping"); + checkState(RunControlState::Stopping); + for (RunWorker *worker : m_workers) { + if (worker) { + debugMessage(" Examining worker " + worker->displayName()); + switch (worker->d->state) { + case RunWorkerState::Initialized: + debugMessage(" " + worker->displayName() + " was Initialized, setting to Done"); + worker->d->state = RunWorkerState::Done; + break; + case RunWorkerState::Stopping: + debugMessage(" " + worker->displayName() + " was already Stopping. Keeping it that way"); + break; + case RunWorkerState::Starting: + worker->d->state = RunWorkerState::Stopping; + debugMessage(" " + worker->displayName() + " was Starting, queuing stop"); + QTimer::singleShot(0, worker, &RunWorker::initiateStop); + return; // Sic. + case RunWorkerState::Running: + debugMessage(" " + worker->displayName() + " was Running, queuing stop"); + worker->d->state = RunWorkerState::Stopping; + QTimer::singleShot(0, worker, &RunWorker::initiateStop); + return; // Sic. + case RunWorkerState::Done: + debugMessage(" " + worker->displayName() + " was Done. Good."); + break; + case RunWorkerState::Failed: + debugMessage(" " + worker->displayName() + " was Failed. Good"); + break; + } + } else { + debugMessage("Found unknown deleted worker"); + } + } + debugMessage("All workers stopped. Set runControl to Stopped"); + setState(RunControlState::Stopped); } -void RunControlPrivate::onToolStopFailed(const QString &msg) +void RunControlPrivate::onWorkerStarted(RunWorker *worker) { - checkState(State::ToolStopping); - targetRunner->onToolFailure(); - debugMessage("Tool stop failed"); + worker->d->state = RunWorkerState::Running; + + if (state == RunControlState::Starting) { + debugMessage(worker->displayName() + " start succeeded"); + continueStart(); + return; + } + showError(tr("Unexpected run control state %1 when worker %2 started") + .arg(stateName(state)) + .arg(worker->displayName())); + //setState(RunControlState::Stopped); +} + +void RunControlPrivate::onWorkerFailed(RunWorker *worker, const QString &msg) +{ + worker->d->state = RunWorkerState::Failed; + showError(msg); - setState(State::Stopped); + setState(RunControlState::Stopped); } -void RunControlPrivate::onTargetStopped() +void RunControlPrivate::onWorkerStopped(RunWorker *worker) { - targetRunner->onStop(); - debugMessage("Target stopped"); - checkState(State::TargetStopping); - setState(State::Stopped); -} - -void RunControlPrivate::onTargetStopFailed(const QString &msg) -{ - debugMessage("Target stop failed"); - checkState(State::TargetStopping); - toolRunner->onTargetFailure(); - showError(msg); - setState(State::Stopped); -} - -void RunControlPrivate::onTargetFailed(const QString &msg) -{ - debugMessage("Target operation failed"); - if (state == State::TargetPreparing) { - onTargetPrepareFailed(msg); - } else if (state == State::TargetStarting) { - onTargetStartFailed(msg); - } else if (state == State::TargetStopping) { - onTargetStopFailed(msg); - } else { - showError(msg); - showError(RunControl::tr("Unexpected state: %1").arg(int(state))); - setState(State::Stopped); - } -} - -void RunControlPrivate::onTargetSuccess() -{ - debugMessage("Target operation successful"); - if (state == State::TargetPreparing) { - onTargetPrepared(); - } else if (state == State::TargetStarting) { - onTargetStarted(); - } else if (state == State::TargetStopping) { - onTargetStopped(); - } else { - showError(RunControl::tr("Unexpected state: %1").arg(int(state))); - setState(State::Stopped); - } -} - -void RunControlPrivate::onToolFailed(const QString &msg) -{ - debugMessage("Tool operation failed"); - if (state == State::ToolPreparing) { - onToolPrepareFailed(msg); - } else if (state == State::ToolStarting) { - onToolStartFailed(msg); - } else if (state == State::ToolStopping) { - onToolStartFailed(msg); - } else { - showError(msg); - showError(RunControl::tr("Unexpected state: %1").arg(int(state))); - setState(State::Stopped); - } -} - -void RunControlPrivate::onToolSuccess() -{ - debugMessage("Tool operation successful"); - if (state == State::ToolPreparing) { - onToolPrepared(); - } else if (state == State::ToolStarting) { - onToolStarted(); - } else if (state == State::ToolStopping) { - onToolStopped(); - } else { - showError(RunControl::tr("Unexpected state: %1").arg(int(state))); - setState(State::Stopped); - } -} - - -void RunControlPrivate::handleFailure() -{ - switch (state) { - case State::Initialized: - case State::TargetPreparing: - case State::ToolPreparing: - case State::TargetStarting: - case State::ToolStarting: - case State::Running: - case State::ToolStopping: - case State::TargetStopping: - case State::Stopped: - setState(State::Stopped); - break; - } + debugMessage(worker->displayName() + " stopped."); + continueStop(); } void RunControlPrivate::showError(const QString &msg) { if (!msg.isEmpty()) - q->appendMessage(msg, ErrorMessageFormat); + q->appendMessage(msg + '\n', ErrorMessageFormat); } Utils::OutputFormatter *RunControl::outputFormatter() const @@ -897,28 +904,6 @@ void RunControl::setConnection(const Connection &connection) d->connection = connection; } -ToolRunner *RunControl::toolRunner() const -{ - return d->toolRunner; -} - -void RunControl::setToolRunner(ToolRunner *tool) -{ - delete d->toolRunner; - d->toolRunner = tool; -} - -TargetRunner *RunControl::targetRunner() const -{ - return d->targetRunner; -} - -void RunControl::setTargetRunner(TargetRunner *runner) -{ - delete d->targetRunner; - d->targetRunner = runner; -} - QString RunControl::displayName() const { return d->displayName; @@ -1028,7 +1013,17 @@ void RunControl::setSupportsReRunning(bool reRunningSupported) bool RunControl::isRunning() const { - return d->state == RunControlPrivate::State::Running; + return d->state == RunControlState::Running; +} + +bool RunControl::isStarting() const +{ + return d->state == RunControlState::Starting; +} + +bool RunControl::isStopping() const +{ + return d->state == RunControlState::Stopping; } /*! @@ -1066,61 +1061,36 @@ bool RunControl::showPromptToStopDialog(const QString &title, return close; } -bool RunControlPrivate::isAllowedTransition(State from, State to) +bool RunControlPrivate::isAllowedTransition(RunControlState from, RunControlState to) { switch (from) { - case State::Initialized: - return to == State::TargetPreparing; - case State::TargetPreparing: - return to == State::ToolPreparing; - case State::ToolPreparing: - return to == State::TargetStarting; - case State::TargetStarting: - return to == State::ToolStarting; - case State::ToolStarting: - return to == State::Running; - case State::Running: - return to == State::ToolStopping - || to == State::Stopped; - case State::ToolStopping: - return to == State::TargetStopping; - case State::TargetStopping: - return to == State::Stopped; - case State::Stopped: + case RunControlState::Initialized: + return to == RunControlState::Starting; + case RunControlState::Starting: + return to == RunControlState::Running; + case RunControlState::Running: + return to == RunControlState::Stopping + || to == RunControlState::Stopped; + case RunControlState::Stopping: + return to == RunControlState::Stopped; + case RunControlState::Stopped: return false; } - qDebug() << "UNKNOWN DEBUGGER STATE:" << from; return false; } -void RunControlPrivate::checkState(State expectedState) +void RunControlPrivate::checkState(RunControlState expectedState) { if (state != expectedState) - qDebug() << "Unexpected state " << expectedState << " have: " << state; + qDebug() << "Unexpected run control state " << stateName(expectedState) + << " have: " << stateName(state); } -QString RunControlPrivate::stateName(State s) const -{ -# define SN(x) case x: return QLatin1String(#x); - switch (s) { - SN(State::Initialized) - SN(State::TargetPreparing) - SN(State::ToolPreparing) - SN(State::TargetStarting) - SN(State::ToolStarting) - SN(State::Running) - SN(State::ToolStopping) - SN(State::TargetStopping) - SN(State::Stopped) - } - return QLatin1String(""); -# undef SN -} - -void RunControlPrivate::setState(State newState) +void RunControlPrivate::setState(RunControlState newState) { if (!isAllowedTransition(state, newState)) - qDebug() << "Invalid run state transition from " << state << " to " << newState; + qDebug() << "Invalid run control state transition from " << stateName(state) + << " to " << stateName(newState); state = newState; @@ -1128,14 +1098,15 @@ void RunControlPrivate::setState(State newState) // Extra reporting. switch (state) { - case State::Running: + case RunControlState::Running: emit q->started(); break; - case State::Stopped: + case RunControlState::Stopped: q->setApplicationProcessHandle(Utils::ProcessHandle()); - toolRunner->onFinished(); - targetRunner->onFinished(); - state = State::Initialized; // Reset for potential re-running. + foreach (auto worker, m_workers) + if (worker) + worker->onFinished(); + //state = RunControlState::Initialized; // Reset for potential re-running. emit q->finished(); break; default: @@ -1145,8 +1116,8 @@ void RunControlPrivate::setState(State newState) void RunControlPrivate::debugMessage(const QString &msg) { - if (debugStates) - q->appendMessage(msg + '\n', Utils::DebugFormat); + //q->appendMessage(msg + '\n', Utils::DebugFormat); + qCDebug(statesLog()) << msg; } /*! @@ -1166,20 +1137,12 @@ void RunControl::bringApplicationToForeground() void RunControl::reportApplicationStart() { - // QTC_CHECK(false); FIXME: Legacy, ToolRunner should emit started() instead. - d->onToolStarted(); - emit started(); + QTC_CHECK(false);// FIXME: Legacy } void RunControl::reportApplicationStop() { - // QTC_CHECK(false); FIXME: Legacy, ToolRunner should emit stopped() instead. - if (d->state == RunControlPrivate::State::Stopped) { - // FIXME: Currently various tool implementations call reportApplicationStop() - // multiple times. Fix it there and then add a soft assert here. - return; - } - d->onTargetStopped(); + QTC_CHECK(false);// FIXME: Legacy } void RunControl::bringApplicationToForegroundInternal() @@ -1222,8 +1185,9 @@ static bool isSynchronousLauncher(RunControl *runControl) // SimpleTargetRunner SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl) - : TargetRunner(runControl) + : RunWorker(runControl) { + setDisplayName("SimpleTargetRunner"); } void SimpleTargetRunner::start() @@ -1231,11 +1195,13 @@ void SimpleTargetRunner::start() m_launcher.disconnect(this); Runnable r = runControl()->runnable(); + QString msg = RunControl::tr("Starting %1...").arg(r.displayName()); + appendMessage(msg, Utils::NormalMessageFormat); if (isSynchronousLauncher(runControl())) { connect(&m_launcher, &ApplicationLauncher::appendMessage, - this, &TargetRunner::appendMessage); + this, &SimpleTargetRunner::appendMessage); connect(&m_launcher, &ApplicationLauncher::processStarted, this, &SimpleTargetRunner::onProcessStarted); connect(&m_launcher, &ApplicationLauncher::processExited, @@ -1249,15 +1215,15 @@ void SimpleTargetRunner::start() reportFailure(RunControl::tr("Executable %1 does not exist.") .arg(QDir::toNativeSeparators(executable))); } else { - QString msg = RunControl::tr("Starting %1...").arg(QDir::toNativeSeparators(executable)) + '\n'; - appendMessage(msg, Utils::NormalMessageFormat); m_launcher.start(r); } } else { connect(&m_launcher, &ApplicationLauncher::reportError, - this, &TargetRunner::reportFailure); + this, [this](const QString &msg) { + reportFailure(msg); + }); connect(&m_launcher, &ApplicationLauncher::remoteStderr, this, [this](const QByteArray &output) { @@ -1272,12 +1238,29 @@ void SimpleTargetRunner::start() connect(&m_launcher, &ApplicationLauncher::finished, this, [this] { m_launcher.disconnect(this); - reportSuccess(); + reportStopped(); + }); + + connect(&m_launcher, &ApplicationLauncher::processStarted, + this, [this] { + appendMessage("Application launcher started", Utils::NormalMessageFormat); +// reportStarted(); + }); + + connect(&m_launcher, &ApplicationLauncher::processExited, + this, [this] { + m_launcher.disconnect(this); + reportStopped(); + }); + + connect(&m_launcher, &ApplicationLauncher::remoteProcessStarted, + this, [this] { + reportStarted(); }); connect(&m_launcher, &ApplicationLauncher::reportProgress, this, [this](const QString &progressString) { - appendMessage(progressString + '\n', Utils::NormalMessageFormat); + appendMessage(progressString, Utils::NormalMessageFormat); }); m_launcher.start(r, runControl()->device()); @@ -1294,145 +1277,190 @@ void SimpleTargetRunner::onProcessStarted() // Console processes only know their pid after being started runControl()->setApplicationProcessHandle(m_launcher.applicationPID()); runControl()->bringApplicationToForeground(); - reportSuccess(); + reportStarted(); } void SimpleTargetRunner::onProcessFinished(int exitCode, QProcess::ExitStatus status) { QString msg; - QString exe = runControl()->runnable().as().executable; if (status == QProcess::CrashExit) - msg = tr("%1 crashed.").arg(QDir::toNativeSeparators(exe)); + msg = tr("%1 crashed."); else - msg = tr("%1 exited with code %2").arg(QDir::toNativeSeparators(exe)).arg(exitCode); - appendMessage(msg + '\n', Utils::NormalMessageFormat); + msg = tr("%2 exited with code %1").arg(exitCode); + appendMessage(msg.arg(runnable().displayName()), Utils::NormalMessageFormat); reportStopped(); } - -// TargetRunner - -TargetRunner::TargetRunner(RunControl *runControl) - : m_runControl(runControl) +void RunControl::reportFailure(const QString &msg) { - runControl->setTargetRunner(this); + d->showError(msg); + d->setState(RunControlState::Stopped); } -TargetRunner::~TargetRunner() +// RunWorkerPrivate + +RunWorkerPrivate::RunWorkerPrivate(RunWorker *runWorker, RunControl *runControl) + : q(runWorker), runControl(runControl) +{ + runControl->d->m_workers.append(runWorker); +} + +bool RunWorkerPrivate::canStart() const +{ + if (state != RunWorkerState::Initialized) + return false; + for (RunWorker *worker : dependencies) { + QTC_ASSERT(worker, return true); + if (worker->d->state != RunWorkerState::Done + && worker->d->state != RunWorkerState::Running) + return false; + } + return true; +} + +void RunWorkerPrivate::timerEvent(QTimerEvent *ev) +{ + if (ev->timerId() == startWatchdogTimerId) { + q->reportFailure(tr("Worker start timed out")); + return; + } + if (ev->timerId() == stopWatchdogTimerId) { + q->reportFailure(tr("Worker stop timed out")); + return; + } +} + +// RunWorker + +RunWorker::RunWorker(RunControl *runControl) + : d(new RunWorkerPrivate(this, runControl)) { } -RunControl *TargetRunner::runControl() const +RunWorker::~RunWorker() { - return m_runControl; + delete d; } -void TargetRunner::appendMessage(const QString &msg, OutputFormat format) +void RunWorker::initiateStart() { - m_runControl->appendMessage(msg, format); + if (d->startWatchdogInterval != 0) + d->startWatchdogTimerId = d->startTimer(d->startWatchdogInterval); + + start(); } -IDevice::ConstPtr TargetRunner::device() const +void RunWorker::reportStarted() { - return m_runControl->device(); + if (d->startWatchdogInterval != 0) + d->killTimer(d->startWatchdogTimerId); + d->runControl->d->onWorkerStarted(this); + emit started(); } -void TargetRunner::prepare() +void RunWorker::initiateStop() { - reportSuccess(); // By default nothing to do, all is fine. + if (d->stopWatchdogInterval != 0) + d->stopWatchdogTimerId = d->startTimer(d->stopWatchdogInterval); + + d->runControl->d->debugMessage("Initiate stop for " + displayName()); + stop(); } -void TargetRunner::start() +void RunWorker::reportStopped() { - reportSuccess(); + if (d->stopWatchdogInterval != 0) + d->killTimer(d->stopWatchdogTimerId); + d->runControl->d->onWorkerStopped(this); + emit stopped(); } -void TargetRunner::stop() +void RunWorker::reportFailure(const QString &msg) { - reportSuccess(); // By default all is fine. + d->runControl->d->onWorkerFailed(this, msg); } -void TargetRunner::reportStopped() +void RunWorker::appendMessage(const QString &msg, OutputFormat format) { - m_runControl->d->onTargetStopped(); + if (msg.endsWith('\n')) + d->runControl->appendMessage(msg, format); + else + d->runControl->appendMessage(msg + '\n', format); } -void TargetRunner::reportSuccess() +IDevice::ConstPtr RunWorker::device() const { - m_runControl->d->onTargetSuccess(); + return d->runControl->device(); } -void TargetRunner::reportFailure(const QString &msg) +const Runnable &RunWorker::runnable() const { - m_runControl->d->onTargetFailed(msg); + return d->runControl->runnable(); } -// ToolRunner - -ToolRunner::ToolRunner(RunControl *runControl) - : m_runControl(runControl) +const Connection &RunWorker::connection() const { - if (runControl) - runControl->setToolRunner(this); + return d->runControl->connection(); } -ToolRunner::~ToolRunner() +Core::Id RunWorker::runMode() const { + return d->runControl->runMode(); } -RunControl *ToolRunner::runControl() const +void RunWorker::addDependency(RunWorker *dependency) { - return m_runControl; + d->dependencies.append(dependency); } -void ToolRunner::appendMessage(const QString &msg, OutputFormat format) +RunControl *RunWorker::runControl() const { - m_runControl->appendMessage(msg, format); + return d->runControl; } -IDevice::ConstPtr ToolRunner::device() const +QString RunWorker::displayName() const { - return m_runControl->device(); + return d->displayName; } -const Runnable &ToolRunner::runnable() const +void RunWorker::setDisplayName(const QString &displayName) { - return m_runControl->runnable(); + d->displayName = displayName; } -const Connection &ToolRunner::connection() const +void RunWorker::setStartTimeout(int ms) { - return m_runControl->connection(); + d->startWatchdogInterval = ms; } -void ToolRunner::prepare() +void RunWorker::setStopTimeout(int ms) { - reportSuccess(); + d->stopWatchdogInterval = ms; } -void ToolRunner::start() +void RunWorker::reportData(int channel, const QVariant &data) { - reportSuccess(); + emit dataReported(channel, data); } -void ToolRunner::stop() +void RunWorker::recordData(const QString &channel, const QVariant &data) { - reportSuccess(); + d->data[channel] = data; } -void ToolRunner::reportStopped() +QVariant RunWorker::recordedData(const QString &channel) { - m_runControl->d->onToolStopped(); + return d->data[channel]; } -void ToolRunner::reportSuccess() +void RunWorker::start() { - m_runControl->d->onToolSuccess(); + reportStarted(); } -void ToolRunner::reportFailure(const QString &msg) +void RunWorker::stop() { - m_runControl->d->onToolFailed(msg); + reportStopped(); } } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index 368e95978fd..17f14e64577 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -51,11 +51,10 @@ class RunConfiguration; class RunConfigWidget; class RunControl; class Target; -class TargetRunner; -class ToolRunner; namespace Internal { class RunControlPrivate; +class RunWorkerPrivate; class SimpleRunControlPrivate; } // Internal @@ -148,6 +147,7 @@ class PROJECTEXPLORER_EXPORT Runnable virtual ~Concept() {} virtual Concept *clone() const = 0; virtual bool canReUseOutputPane(const std::unique_ptr &other) const = 0; + virtual QString displayName() const = 0; virtual void *typeId() const = 0; }; @@ -168,6 +168,8 @@ class PROJECTEXPLORER_EXPORT Runnable return m_data == that->m_data; } + QString displayName() const override { return m_data.displayName(); } + void *typeId() const override { return T::staticTypeId; } T m_data; @@ -190,6 +192,7 @@ public: } bool canReUseOutputPane(const Runnable &other) const; + QString displayName() const { return d->displayName(); } private: std::unique_ptr d; @@ -351,6 +354,61 @@ signals: void displayNameChanged(const QString &); }; +class PROJECTEXPLORER_EXPORT RunWorker : public QObject +{ + Q_OBJECT + +public: + explicit RunWorker(RunControl *runControl); + ~RunWorker() override; + + RunControl *runControl() const; + + void addDependency(RunWorker *dependency); + + QString displayName() const; + void setDisplayName(const QString &displayName); + + void setStartTimeout(int ms); + void setStopTimeout(int ms); + + void reportData(int channel, const QVariant &data); + + void recordData(const QString &channel, const QVariant &data); + QVariant recordedData(const QString &channel); + + // Part of read-only interface of RunControl for convenience. + void appendMessage(const QString &msg, Utils::OutputFormat format); + IDevice::ConstPtr device() const; + const Runnable &runnable() const; + const Connection &connection() const; + Core::Id runMode() const; + + // States + void initiateStart(); + void reportStarted(); + + void initiateStop(); + void reportStopped(); + + void reportFailure(const QString &msg = QString()); + +signals: + void dataReported(int channel, const QVariant &data); + void started(); + void stopped(); + +protected: + void virtual start(); + void virtual stop(); + void virtual onFinished() {} + +private: + friend class Internal::RunControlPrivate; + friend class Internal::RunWorkerPrivate; + Internal::RunWorkerPrivate *d; +}; + /** * A RunControl controls the running of an application or tool * on a target device. It controls start and stop, and handles @@ -380,6 +438,8 @@ public: void setDisplayName(const QString &displayName); bool isRunning() const; + bool isStarting() const; + bool isStopping() const; void setIcon(const Utils::Icon &icon); Utils::Icon icon() const; @@ -402,12 +462,6 @@ public: const Connection &connection() const; void setConnection(const Connection &connection); - ToolRunner *toolRunner() const; - void setToolRunner(ToolRunner *tool); - - TargetRunner *targetRunner() const; - void setTargetRunner(TargetRunner *tool); - virtual void appendMessage(const QString &msg, Utils::OutputFormat format); virtual void bringApplicationToForeground(); @@ -415,8 +469,9 @@ public: virtual void notifyRemoteSetupFailed(const QString &) {} // Same. virtual void notifyRemoteFinished() {} // Same. - void reportApplicationStart(); // Call this when the application starts to run - void reportApplicationStop(); // Call this when the application has stopped for any reason + void reportApplicationStart(); // FIXME: Don't use + void reportApplicationStop(); // FIXME: Don't use + void reportFailure(const QString &msg = QString()); static bool showPromptToStopDialog(const QString &title, const QString &text, const QString &stopButtonText = QString(), @@ -426,6 +481,25 @@ public: virtual void start(); virtual void stop(); + using WorkerCreator = std::function; + static void registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator); + RunWorker *workerById(Core::Id id) const; + QList> workers() const; + + template T *worker() const { + for (const QPointer &worker : workers()) { + if (worker) { + if (auto res = qobject_cast(worker.data())) + return res; + } + } + return nullptr; + } + + using RunWorkerCreator = std::function; + static void registerRunWorkerCreator(Core::Id id, const RunWorkerCreator &creator); + RunWorker *createWorker(Core::Id id); + signals: void appendMessageRequested(ProjectExplorer::RunControl *runControl, const QString &msg, Utils::OutputFormat format); @@ -436,114 +510,29 @@ signals: void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle private: - friend class Internal::RunControlPrivate; - friend class TargetRunner; - friend class ToolRunner; + friend class RunWorker; + friend class Internal::RunWorkerPrivate; void bringApplicationToForegroundInternal(); Internal::RunControlPrivate *d; }; -/** - * A base for target-specific additions to the RunControl. - */ - -class PROJECTEXPLORER_EXPORT TargetRunner : public QObject -{ - Q_OBJECT - -public: - explicit TargetRunner(RunControl *runControl); - ~TargetRunner() override; - - RunControl *runControl() const; - void appendMessage(const QString &msg, Utils::OutputFormat format); - IDevice::ConstPtr device() const; - - // Preparation phase. - virtual void prepare(); // Initiate setup. Needs to report result. - // Startup phase. - virtual void start(); // Initiates start. Needs to report result. - // Stopping phase. - virtual void stop(); // Initiates stop. Needs to report result. - - // - void reportStopped(); - // Generic success report, proceed to next stage. - void reportSuccess(); - // Generic error, start ramp down. - void reportFailure(const QString &msg = QString()); - - // Customization points. No reporting required nor wanted. - virtual void onStop() {} - virtual void onToolFailure() {} - virtual void onTargetFailure() {} - virtual void onFinished() {} - -private: - QPointer m_runControl; -}; - -/** - * A base for tool-specific additions to RunControl. - */ - -class PROJECTEXPLORER_EXPORT ToolRunner : public QObject -{ - Q_OBJECT - -public: - explicit ToolRunner(RunControl *runControl); - ~ToolRunner() override; - - RunControl *runControl() const; - - // Part of read-only interface of RunControl for convenience. - void appendMessage(const QString &msg, Utils::OutputFormat format); - IDevice::ConstPtr device() const; - const Runnable &runnable() const; - const Connection &connection() const; - - // Preparation phase. - virtual void prepare(); // Initiates preparation, needs to report success or failure. - // Start phase. - virtual void start(); - // Stop phase. - virtual void stop(); - - // - void reportStopped(); - // Generic success report, proceed to next stage. - void reportSuccess(); - // Generic error, start ramp down. - void reportFailure(const QString &msg = QString()); - - // Customization points. No reporting required nor wanted. - virtual void onStop() {} - virtual void onToolFailure() {} - virtual void onTargetFailure() {} - virtual void onFinished() {} - -private: - QPointer m_runControl; -}; /** * A simple TargetRunner for cases where a plain ApplicationLauncher is * sufficient for running purposes. */ -class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public TargetRunner +class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public RunWorker { public: explicit SimpleTargetRunner(RunControl *runControl); - ApplicationLauncher *applicationLauncher() { return &m_launcher; } - -private: +protected: void start() override; void stop() override; +private: void onProcessStarted(); void onProcessFinished(int exitCode, QProcess::ExitStatus status); diff --git a/src/plugins/projectexplorer/runnables.h b/src/plugins/projectexplorer/runnables.h index 088a6a872db..3d286a8b838 100644 --- a/src/plugins/projectexplorer/runnables.h +++ b/src/plugins/projectexplorer/runnables.h @@ -32,6 +32,7 @@ #include +#include #include namespace ProjectExplorer { @@ -46,6 +47,7 @@ public: ApplicationLauncher::Mode runMode = ApplicationLauncher::Gui; IDevice::ConstPtr device; // Override the kit's device. Keep unset by default. + QString displayName() const { return QDir::toNativeSeparators(executable); } static void *staticTypeId; }; diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index aa2af74b791..bc537fbb781 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -67,7 +67,6 @@ namespace QmlProfiler { class QmlProfilerRunControl::QmlProfilerRunControlPrivate { public: - Internal::QmlProfilerTool *m_tool = 0; QmlProfilerStateManager *m_profilerState = 0; QTimer m_noDebugOutputTimer; }; @@ -76,15 +75,13 @@ public: // QmlProfilerRunControl // -QmlProfilerRunControl::QmlProfilerRunControl(RunConfiguration *runConfiguration, - Internal::QmlProfilerTool *tool) +QmlProfilerRunControl::QmlProfilerRunControl(RunConfiguration *runConfiguration) : RunControl(runConfiguration, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) , d(new QmlProfilerRunControlPrivate) { setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); setSupportsReRunning(false); - d->m_tool = tool; // Only wait 4 seconds for the 'Waiting for connection' on application output, then just try to connect // (application output might be redirected / blocked) d->m_noDebugOutputTimer.setSingleShot(true); @@ -104,7 +101,7 @@ QmlProfilerRunControl::~QmlProfilerRunControl() void QmlProfilerRunControl::start() { reportApplicationStart(); - d->m_tool->finalizeRunControl(this); + Internal::QmlProfilerTool::instance()->finalizeRunControl(this); QTC_ASSERT(d->m_profilerState, reportApplicationStop(); return); QTC_ASSERT(connection().is(), reportApplicationStop(); return); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h index 69686a1e351..9ece8c50675 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h @@ -32,15 +32,12 @@ namespace QmlProfiler { -namespace Internal { class QmlProfilerTool; } - class QmlProfilerRunControl : public ProjectExplorer::RunControl { Q_OBJECT public: - QmlProfilerRunControl(ProjectExplorer::RunConfiguration *runConfiguration, - Internal::QmlProfilerTool *tool); + QmlProfilerRunControl(ProjectExplorer::RunConfiguration *runConfiguration); ~QmlProfilerRunControl() override; void registerProfilerStateManager( QmlProfilerStateManager *profilerState ); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp index e489c3b5aa8..577564f3d27 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp @@ -92,10 +92,7 @@ RunControl *QmlProfilerRunControlFactory::create(RunConfiguration *runConfigurat connection.analyzerPort = LocalQmlProfilerRunner::findFreePort(connection.analyzerHost); } - auto runControl = qobject_cast - (Debugger::createAnalyzerRunControl(runConfiguration, mode)); - QTC_ASSERT(runControl, return 0); - + auto runControl = new QmlProfilerRunControl(runConfiguration); runControl->setRunnable(runnable); runControl->setConnection(connection); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index dc7b580a62a..09d884e4d16 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -127,9 +127,12 @@ public: bool m_toolBusy = false; }; +static QmlProfilerTool *s_instance; + QmlProfilerTool::QmlProfilerTool(QObject *parent) : QObject(parent), d(new QmlProfilerToolPrivate) { + s_instance = this; setObjectName(QLatin1String("QmlProfilerTool")); d->m_profilerState = new QmlProfilerStateManager(this); @@ -244,8 +247,9 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) // is available, then we can populate the file finder d->m_profilerModelManager->populateFileFinder(); - auto runControlCreator = [this](RunConfiguration *runConfiguration, Core::Id) { - return createRunControl(runConfiguration); + auto runWorkerCreator = [this](RunControl *runControl) { +// return createRunControl(runConfiguration); + return nullptr; // FIXME }; QString description = tr("The QML Profiler can be used to find performance " @@ -254,7 +258,7 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) d->m_startAction = Debugger::createStartAction(); d->m_stopAction = Debugger::createStopAction(); - Debugger::registerAction(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, runControlCreator); + RunControl::registerWorkerCreator(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, runWorkerCreator); act = new QAction(tr("QML Profiler"), this); act->setToolTip(description); menu->addAction(ActionManager::registerAction(act, "QmlProfiler.Local"), @@ -270,7 +274,6 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) act->setEnabled(d->m_startAction->isEnabled()); }); - Debugger::registerAction(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, runControlCreator); act = new QAction(tr("QML Profiler (External)"), this); act->setToolTip(description); menu->addAction(ActionManager::registerAction(act, "QmlProfiler.Remote"), @@ -305,6 +308,11 @@ QmlProfilerTool::~QmlProfilerTool() delete d; } +QmlProfilerTool *QmlProfilerTool::instance() +{ + return s_instance; +} + void QmlProfilerTool::updateRunActions() { if (d->m_toolBusy) { @@ -336,11 +344,11 @@ RunControl *QmlProfilerTool::createRunControl(RunConfiguration *runConfiguration } } - auto runControl = new QmlProfilerRunControl(runConfiguration, this); + auto runControl = new QmlProfilerRunControl(runConfiguration); connect(runControl, &RunControl::finished, this, [this, runControl] { d->m_toolBusy = false; updateRunActions(); - disconnect(d->m_stopAction, &QAction::triggered, runControl, &QmlProfilerRunControl::stop); + disconnect(d->m_stopAction, &QAction::triggered, runControl, &RunControl::stop); }); connect(d->m_stopAction, &QAction::triggered, runControl, &QmlProfilerRunControl::stop); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.h b/src/plugins/qmlprofiler/qmlprofilertool.h index 85715f81200..c9600051b3f 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.h +++ b/src/plugins/qmlprofiler/qmlprofilertool.h @@ -49,6 +49,8 @@ public: explicit QmlProfilerTool(QObject *parent); ~QmlProfilerTool(); + static QmlProfilerTool *instance(); + ProjectExplorer::RunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration = 0); void finalizeRunControl(QmlProfilerRunControl *runControl); diff --git a/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp b/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp index c7ef5f1b4ec..2171f45f60d 100644 --- a/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp +++ b/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp @@ -24,6 +24,9 @@ ****************************************************************************/ #include "localqmlprofilerrunner_test.h" + +#include "../qmlprofilerruncontrol.h" + #include #include #include @@ -57,8 +60,7 @@ void LocalQmlProfilerRunnerTest::testRunner() // should not be used anywhere but cannot be empty configuration.socket = connection.analyzerSocket = QString("invalid"); - rc = Debugger::createAnalyzerRunControl( - nullptr, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); + rc = new QmlProfilerRunControl(nullptr); rc->setConnection(connection); auto runner = new LocalQmlProfilerRunner(configuration, rc); connectRunner(runner); @@ -79,8 +81,7 @@ void LocalQmlProfilerRunnerTest::testRunner1() configuration.debuggee.commandLineArguments = QString("-test QmlProfiler,"); delete rc; - rc = Debugger::createAnalyzerRunControl( - nullptr, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); + rc = new QmlProfilerRunControl(nullptr); rc->setConnection(connection); auto runner = new LocalQmlProfilerRunner(configuration, rc); connectRunner(runner); @@ -100,8 +101,7 @@ void LocalQmlProfilerRunnerTest::testRunner2() connection.analyzerSocket.clear(); configuration.port = connection.analyzerPort = LocalQmlProfilerRunner::findFreePort(connection.analyzerHost); - rc = Debugger::createAnalyzerRunControl( - nullptr, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); + rc = new QmlProfilerRunControl(nullptr); rc->setConnection(connection); auto runner = new LocalQmlProfilerRunner(configuration, rc); connectRunner(runner); diff --git a/src/plugins/qnx/qnx.pro b/src/plugins/qnx/qnx.pro index 64874c929a4..b50f4b27fb4 100644 --- a/src/plugins/qnx/qnx.pro +++ b/src/plugins/qnx/qnx.pro @@ -9,13 +9,11 @@ SOURCES += qnxplugin.cpp \ qnxdevicewizard.cpp \ qnxrunconfiguration.cpp \ qnxruncontrolfactory.cpp \ - qnxabstractrunsupport.cpp \ qnxanalyzesupport.cpp \ qnxdebugsupport.cpp \ qnxdeploystepfactory.cpp \ qnxdeployconfigurationfactory.cpp \ qnxrunconfigurationfactory.cpp \ - qnxruncontrol.cpp \ qnxqtversionfactory.cpp \ qnxqtversion.cpp \ qnxdeployconfiguration.cpp \ @@ -44,13 +42,11 @@ HEADERS += qnxplugin.h\ qnxdevicewizard.h \ qnxrunconfiguration.h \ qnxruncontrolfactory.h \ - qnxabstractrunsupport.h \ qnxanalyzesupport.h \ qnxdebugsupport.h \ qnxdeploystepfactory.h \ qnxdeployconfigurationfactory.h \ qnxrunconfigurationfactory.h \ - qnxruncontrol.h \ qnxqtversionfactory.h \ qnxqtversion.h \ qnxdeployconfiguration.h \ diff --git a/src/plugins/qnx/qnx.qbs b/src/plugins/qnx/qnx.qbs index d57a93259bd..eee52f0f5d1 100644 --- a/src/plugins/qnx/qnx.qbs +++ b/src/plugins/qnx/qnx.qbs @@ -33,8 +33,6 @@ QtcPlugin { "qnxconstants.h", "qnxconfiguration.cpp", "qnxconfiguration.h", - "qnxabstractrunsupport.cpp", - "qnxabstractrunsupport.h", "qnxanalyzesupport.cpp", "qnxanalyzesupport.h", "qnxdebugsupport.cpp", @@ -78,8 +76,6 @@ QtcPlugin { "qnxrunconfiguration.h", "qnxrunconfigurationfactory.cpp", "qnxrunconfigurationfactory.h", - "qnxruncontrol.cpp", - "qnxruncontrol.h", "qnxruncontrolfactory.cpp", "qnxruncontrolfactory.h", "qnxutils.cpp", diff --git a/src/plugins/qnx/qnxabstractrunsupport.cpp b/src/plugins/qnx/qnxabstractrunsupport.cpp deleted file mode 100644 index 52d2110bb45..00000000000 --- a/src/plugins/qnx/qnxabstractrunsupport.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "qnxabstractrunsupport.h" -#include "qnxrunconfiguration.h" - -#include -#include -#include -#include -#include - -using namespace ProjectExplorer; -using namespace RemoteLinux; - -namespace Qnx { -namespace Internal { - -QnxAbstractRunSupport::QnxAbstractRunSupport(RunControl *runControl) - : ToolRunner(runControl) - , m_state(Inactive) -{ - m_launcher = new ApplicationLauncher(this); - m_portsGatherer = new DeviceUsedPortsGatherer(this); - - connect(m_portsGatherer, &DeviceUsedPortsGatherer::error, - this, &QnxAbstractRunSupport::handleError); - connect(m_portsGatherer, &DeviceUsedPortsGatherer::portListReady, - this, &QnxAbstractRunSupport::handlePortListReady); -} - -void QnxAbstractRunSupport::handleAdapterSetupRequested() -{ - QTC_ASSERT(m_state == Inactive, return); - - m_state = GatheringPorts; - m_portsGatherer->start(m_device); -} - -void QnxAbstractRunSupport::handlePortListReady() -{ - QTC_ASSERT(m_state == GatheringPorts, return); - m_portList = device()->freePorts(); - startExecution(); -} - -void QnxAbstractRunSupport::handleRemoteProcessStarted() -{ - m_state = Running; -} - -void QnxAbstractRunSupport::handleRemoteProcessFinished(bool) -{ -} - -void QnxAbstractRunSupport::setFinished() -{ - if (m_state != GatheringPorts && m_state != Inactive) - m_launcher->stop(); - - m_state = Inactive; -} - -QnxAbstractRunSupport::State QnxAbstractRunSupport::state() const -{ - return m_state; -} - -void QnxAbstractRunSupport::setState(QnxAbstractRunSupport::State state) -{ - m_state = state; -} - -ApplicationLauncher *QnxAbstractRunSupport::appRunner() const -{ - return m_launcher; -} - -void QnxAbstractRunSupport::handleProgressReport(const QString &) -{ -} - -void QnxAbstractRunSupport::handleRemoteOutput(const QByteArray &) -{ -} - -void QnxAbstractRunSupport::handleError(const QString &) -{ -} - -bool QnxAbstractRunSupport::setPort(Utils::Port &port) -{ - port = m_portsGatherer->getNextFreePort(&m_portList); - if (!port.isValid()) { - handleError(tr("Not enough free ports on device for debugging.")); - return false; - } - return true; -} - -} // namespace Internal -} // namespace Qnx diff --git a/src/plugins/qnx/qnxabstractrunsupport.h b/src/plugins/qnx/qnxabstractrunsupport.h deleted file mode 100644 index f0e9a58c5b4..00000000000 --- a/src/plugins/qnx/qnxabstractrunsupport.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include -#include - -#include -#include - -#include -#include - -namespace ProjectExplorer { -class ApplicationLauncher; -class DeviceUsedPortsGatherer; -} - -namespace Qnx { -namespace Internal { - -class QnxAbstractRunSupport : public ProjectExplorer::ToolRunner -{ - Q_OBJECT -protected: - enum State { - Inactive, - GatheringPorts, - StartingRemoteProcess, - Running - }; - -public: - explicit QnxAbstractRunSupport(ProjectExplorer::RunControl *runControl); - -protected: - bool setPort(Utils::Port &port); - virtual void startExecution() = 0; - - void setFinished(); - - State state() const; - void setState(State state); - - ProjectExplorer::ApplicationLauncher *appRunner() const; - -public slots: - virtual void handleAdapterSetupRequested(); - - virtual void handleRemoteProcessStarted(); - virtual void handleRemoteProcessFinished(bool); - virtual void handleProgressReport(const QString &progressOutput); - virtual void handleRemoteOutput(const QByteArray &output); - virtual void handleError(const QString &); - -private slots: - void handlePortListReady(); - -private: - ProjectExplorer::DeviceUsedPortsGatherer * m_portsGatherer; - Utils::PortList m_portList; - ProjectExplorer::IDevice::ConstPtr m_device; - ProjectExplorer::ApplicationLauncher *m_launcher; - State m_state; -}; - -} // namespace Internal -} // namespace Qnx diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp index 59ee41810db..52150107906 100644 --- a/src/plugins/qnx/qnxanalyzesupport.cpp +++ b/src/plugins/qnx/qnxanalyzesupport.cpp @@ -29,12 +29,15 @@ #include "qnxrunconfiguration.h" #include "slog2inforunner.h" +#include #include +#include #include #include #include #include +#include using namespace ProjectExplorer; using namespace Utils; @@ -42,122 +45,64 @@ using namespace Utils; namespace Qnx { namespace Internal { -QnxAnalyzeSupport::QnxAnalyzeSupport(RunControl *runControl) - : QnxAbstractRunSupport(runControl) - , m_runnable(runControl->runnable().as()) - , m_qmlPort(-1) +class QnxAnalyzeeRunner : public ProjectExplorer::SimpleTargetRunner { - const ApplicationLauncher *runner = appRunner(); - connect(runner, &ApplicationLauncher::reportError, - this, &QnxAnalyzeSupport::handleError); - connect(runner, &ApplicationLauncher::remoteProcessStarted, - this, &QnxAbstractRunSupport::handleRemoteProcessStarted); - connect(runner, &ApplicationLauncher::finished, - this, &QnxAnalyzeSupport::handleRemoteProcessFinished); - connect(runner, &ApplicationLauncher::reportProgress, - this, &QnxAnalyzeSupport::handleProgressReport); - connect(runner, &ApplicationLauncher::remoteStdout, - this, &QnxAnalyzeSupport::handleRemoteOutput); - connect(runner, &ApplicationLauncher::remoteStderr, - this, &QnxAnalyzeSupport::handleRemoteOutput); - - connect(runControl, &RunControl::starting, - this, &QnxAnalyzeSupport::handleAdapterSetupRequested); - connect(runControl, &RunControl::finished, - this, &QnxAnalyzeSupport::setFinished); - - connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, - this, &QnxAnalyzeSupport::remoteIsRunning); - - IDevice::ConstPtr dev = DeviceKitInformation::device(runControl->runConfiguration()->target()->kit()); - QnxDevice::ConstPtr qnxDevice = dev.dynamicCast(); - - auto qnxRunConfig = qobject_cast(runControl->runConfiguration()); - const QString applicationId = FileName::fromString(qnxRunConfig->remoteExecutableFilePath()).fileName(); - m_slog2Info = new Slog2InfoRunner(applicationId, qnxDevice, this); - connect(m_slog2Info, &Slog2InfoRunner::output, - this, &QnxAnalyzeSupport::showMessage); - connect(runner, &ApplicationLauncher::remoteProcessStarted, - m_slog2Info, &Slog2InfoRunner::start); - if (qnxDevice->qnxVersion() > 0x060500) - connect(m_slog2Info, &Slog2InfoRunner::commandMissing, - this, &QnxAnalyzeSupport::printMissingWarning); -} - -void QnxAnalyzeSupport::handleAdapterSetupRequested() -{ - QTC_ASSERT(state() == Inactive, return); - - showMessage(tr("Preparing remote side...") + QLatin1Char('\n'), NormalMessageFormat); - QnxAbstractRunSupport::handleAdapterSetupRequested(); -} - -void QnxAnalyzeSupport::startExecution() -{ - if (state() == Inactive) - return; - - if (!setPort(m_qmlPort) && !m_qmlPort.isValid()) - return; - - setState(StartingRemoteProcess); - - StandardRunnable r = m_runnable; - if (!r.commandLineArguments.isEmpty()) - r.commandLineArguments += QLatin1Char(' '); - r.commandLineArguments += QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, - m_qmlPort); - appRunner()->start(r, device()); -} - -void QnxAnalyzeSupport::handleRemoteProcessFinished(bool success) -{ - if (!success) - showMessage(tr("The %1 process closed unexpectedly.").arg(m_runnable.executable), - NormalMessageFormat); - runControl()->notifyRemoteFinished(); - - m_slog2Info->stop(); -} - -void QnxAnalyzeSupport::handleProgressReport(const QString &progressOutput) -{ - showMessage(progressOutput + QLatin1Char('\n'), NormalMessageFormat); -} - -void QnxAnalyzeSupport::handleRemoteOutput(const QByteArray &output) -{ - QTC_ASSERT(state() == Inactive || state() == Running, return); - - showMessage(QString::fromUtf8(output), StdOutFormat); -} - -void QnxAnalyzeSupport::handleError(const QString &error) -{ - if (state() == Running) { - showMessage(error, ErrorMessageFormat); - } else if (state() != Inactive) { - showMessage(tr("Initial setup failed: %1").arg(error), NormalMessageFormat); - setFinished(); +public: + QnxAnalyzeeRunner(ProjectExplorer::RunControl *runControl) + : SimpleTargetRunner(runControl) + { + setDisplayName("QnxAnalyzeeRunner"); } + +private: + void start() override + { + auto portsGatherer = runControl()->worker(); + Utils::Port port = portsGatherer->findPort(); + + auto r = runnable().as(); + if (!r.commandLineArguments.isEmpty()) + r.commandLineArguments += ' '; + r.commandLineArguments += + QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, port); + + runControl()->setRunnable(r); + + SimpleTargetRunner::start(); + } +}; + + +// QnxDebugSupport + +QnxAnalyzeSupport::QnxAnalyzeSupport(RunControl *runControl) + : RunWorker(runControl) +{ + setDisplayName("QnxAnalyzeSupport"); + appendMessage(tr("Preparing remote side..."), Utils::LogMessageFormat); + + auto portsGatherer = new PortsGatherer(runControl); + + auto debuggeeRunner = new QnxAnalyzeeRunner(runControl); + debuggeeRunner->addDependency(portsGatherer); + + auto slog2InfoRunner = new Slog2InfoRunner(runControl); + slog2InfoRunner->addDependency(debuggeeRunner); + + addDependency(slog2InfoRunner); + + // QmlDebug::QmlOutputParser m_outputParser; + // FIXME: m_outputParser needs to be fed with application output + // connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, + // this, &QnxAnalyzeSupport::remoteIsRunning); + + // m_outputParser.processOutput(msg); } -void QnxAnalyzeSupport::remoteIsRunning() +void QnxAnalyzeSupport::start() { - runControl()->notifyRemoteSetupDone(m_qmlPort); -} - -void QnxAnalyzeSupport::showMessage(const QString &msg, OutputFormat format) -{ - if (state() != Inactive) - runControl()->appendMessage(msg, format); - m_outputParser.processOutput(msg); -} - -void QnxAnalyzeSupport::printMissingWarning() -{ - showMessage(tr("Warning: \"slog2info\" is not found on the device, debug output not available."), - ErrorMessageFormat); + // runControl()->notifyRemoteSetupDone(m_qmlPort); + reportStarted(); } } // namespace Internal diff --git a/src/plugins/qnx/qnxanalyzesupport.h b/src/plugins/qnx/qnxanalyzesupport.h index bd665c84362..cb049866f8e 100644 --- a/src/plugins/qnx/qnxanalyzesupport.h +++ b/src/plugins/qnx/qnxanalyzesupport.h @@ -25,18 +25,14 @@ #pragma once -#include "qnxabstractrunsupport.h" - -#include -#include -#include +#include namespace Qnx { namespace Internal { class Slog2InfoRunner; -class QnxAnalyzeSupport : public QnxAbstractRunSupport +class QnxAnalyzeSupport : public ProjectExplorer::RunWorker { Q_OBJECT @@ -44,24 +40,7 @@ public: explicit QnxAnalyzeSupport(ProjectExplorer::RunControl *runControl); private: - void handleAdapterSetupRequested() override; - - void handleRemoteProcessFinished(bool success) override; - void handleProgressReport(const QString &progressOutput) override; - void handleRemoteOutput(const QByteArray &output) override; - void handleError(const QString &error) override; - - void showMessage(const QString &, Utils::OutputFormat); - void printMissingWarning(); - - void remoteIsRunning(); - void startExecution() override; - - ProjectExplorer::StandardRunnable m_runnable; - QmlDebug::QmlOutputParser m_outputParser; - Utils::Port m_qmlPort; - - Slog2InfoRunner *m_slog2Info; + void start() override; }; } // namespace Internal diff --git a/src/plugins/qnx/qnxattachdebugsupport.cpp b/src/plugins/qnx/qnxattachdebugsupport.cpp index 2a0d57531dc..5319b14d80d 100644 --- a/src/plugins/qnx/qnxattachdebugsupport.cpp +++ b/src/plugins/qnx/qnxattachdebugsupport.cpp @@ -146,9 +146,9 @@ void QnxAttachDebugSupport::attachToProcess() stopPDebug(); return; } - connect(qobject_cast(runControl->toolRunner()), - &Debugger::DebuggerRunTool::stateChanged, - this, &QnxAttachDebugSupport::handleDebuggerStateChanged); +// connect(qobject_cast(runControl->toolRunner()), +// &Debugger::DebuggerRunTool::stateChanged, +// this, &QnxAttachDebugSupport::handleDebuggerStateChanged); ProjectExplorerPlugin::startRunControl(runControl); } diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index 5099c2224f1..f86c20647c8 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -28,182 +28,123 @@ #include "qnxdevice.h" #include "qnxrunconfiguration.h" #include "slog2inforunner.h" +#include "qnxqtversion.h" +#include "qnxutils.h" -#include #include -#include + +#include #include #include #include #include + +#include +#include + #include #include -#include +using namespace Debugger; using namespace ProjectExplorer; namespace Qnx { namespace Internal { -QnxDebugSupport::QnxDebugSupport(RunControl *runControl) - : QnxAbstractRunSupport(runControl) +// QnxDebuggeeRunner + +class QnxDebuggeeRunner : public ProjectExplorer::SimpleTargetRunner { - auto runConfig = runControl->runConfiguration(); - m_useCppDebugger = runConfig->extraAspect()->useCppDebugger(); - m_useQmlDebugger = runConfig->extraAspect()->useQmlDebugger(); - m_runnable = runConfig->runnable().as(); +public: + QnxDebuggeeRunner(ProjectExplorer::RunControl *runControl) + : SimpleTargetRunner(runControl) + { + setDisplayName("QnxDebuggeeRunner"); + } - const ApplicationLauncher *runner = appRunner(); - connect(runner, &ApplicationLauncher::reportError, this, &QnxDebugSupport::handleError); - connect(runner, &ApplicationLauncher::remoteProcessStarted, this, &QnxDebugSupport::handleRemoteProcessStarted); - connect(runner, &ApplicationLauncher::finished, this, &QnxDebugSupport::handleRemoteProcessFinished); - connect(runner, &ApplicationLauncher::reportProgress, this, &QnxDebugSupport::handleProgressReport); - connect(runner, &ApplicationLauncher::remoteStdout, this, &QnxDebugSupport::handleRemoteOutput); - connect(runner, &ApplicationLauncher::remoteStderr, this, &QnxDebugSupport::handleRemoteOutput); +private: + void start() override + { + auto portsGatherer = runControl()->worker(); - connect(toolRunner(), &Debugger::DebuggerRunTool::requestRemoteSetup, - this, &QnxDebugSupport::handleAdapterSetupRequested); - connect(runControl, &RunControl::finished, - this, &QnxDebugSupport::handleDebuggingFinished); - - auto qnxRunConfig = qobject_cast(runControl->runConfiguration()); - const QString applicationId = Utils::FileName::fromString(qnxRunConfig->remoteExecutableFilePath()).fileName(); - IDevice::ConstPtr dev = DeviceKitInformation::device(runConfig->target()->kit()); - QnxDevice::ConstPtr qnxDevice = dev.dynamicCast(); - - m_slog2Info = new Slog2InfoRunner(applicationId, qnxDevice, this); - connect(m_slog2Info, &Slog2InfoRunner::output, this, &QnxDebugSupport::handleApplicationOutput); - connect(runner, &ApplicationLauncher::remoteProcessStarted, m_slog2Info, &Slog2InfoRunner::start); - if (qnxDevice->qnxVersion() > 0x060500) - connect(m_slog2Info, &Slog2InfoRunner::commandMissing, this, &QnxDebugSupport::printMissingWarning); -} - -void QnxDebugSupport::handleAdapterSetupRequested() -{ - QTC_ASSERT(state() == Inactive, return); - - toolRunner()->showMessage(tr("Preparing remote side...") + '\n', Debugger::AppStuff); - QnxAbstractRunSupport::handleAdapterSetupRequested(); -} - -void QnxDebugSupport::startExecution() -{ - if (state() == Inactive) - return; - - if (m_useCppDebugger && !setPort(m_pdebugPort)) - return; - if (m_useQmlDebugger && !setPort(m_qmlPort)) - return; - - setState(StartingRemoteProcess); - - StandardRunnable r = m_runnable; - QStringList arguments; - if (m_useCppDebugger) - arguments << QString::number(m_pdebugPort.number()); - else { - if (m_useQmlDebugger) { + StandardRunnable r = runnable().as(); + QStringList arguments; + if (portsGatherer->useGdbServer()) { + Utils::Port pdebugPort = portsGatherer->gdbServerPort(); + r.executable = Constants::QNX_DEBUG_EXECUTABLE; + arguments.append(pdebugPort.toString()); + } + if (portsGatherer->useQmlServer()) { arguments.append(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices, - m_qmlPort)); + portsGatherer->qmlServerPort())); } arguments.append(Utils::QtcProcess::splitArgs(r.commandLineArguments)); + r.commandLineArguments = Utils::QtcProcess::joinArgs(arguments); + + SimpleTargetRunner::start(); + } +}; + + +// QnxDebugSupport + +QnxDebugSupport::QnxDebugSupport(RunControl *runControl) + : DebuggerRunTool(runControl) +{ + setDisplayName("QnxDebugSupport"); + appendMessage(tr("Preparing remote side..."), Utils::LogMessageFormat); + + auto portsGatherer = new GdbServerPortsGatherer(runControl); + portsGatherer->setUseGdbServer(isCppDebugging()); + portsGatherer->setUseQmlServer(isQmlDebugging()); + + auto debuggeeRunner = new QnxDebuggeeRunner(runControl); + debuggeeRunner->addDependency(portsGatherer); + + auto slog2InfoRunner = new Slog2InfoRunner(runControl); + slog2InfoRunner->addDependency(debuggeeRunner); + + addDependency(slog2InfoRunner); +} + +void QnxDebugSupport::start() +{ + auto portsGatherer = runControl()->worker(); + Utils::Port pdebugPort = portsGatherer->gdbServerPort(); + + auto runConfig = qobject_cast(runControl()->runConfiguration()); + QTC_ASSERT(runConfig, return); + Target *target = runConfig->target(); + Kit *k = target->kit(); + + DebuggerStartParameters params; + params.startMode = AttachToRemoteServer; + params.useCtrlCStub = true; + params.inferior.executable = runConfig->remoteExecutableFilePath(); + params.symbolFile = runConfig->localExecutableFilePath(); + params.remoteChannel = QString("%1:%2").arg(device()->sshParameters().host).arg(pdebugPort.number()); + params.closeMode = KillAtClose; + params.inferior.commandLineArguments = runConfig->arguments(); + + if (isQmlDebugging()) { + params.qmlServer.host = device()->sshParameters().host; + params.qmlServer.port = portsGatherer->qmlServerPort(); + params.inferior.commandLineArguments.replace("%qml_port%", params.qmlServer.port.toString()); } - r.executable = processExecutable(); - r.commandLineArguments = Utils::QtcProcess::joinArgs(arguments); - r.environment = m_runnable.environment; - r.workingDirectory = m_runnable.workingDirectory; - appRunner()->start(r, device()); + auto qtVersion = dynamic_cast(QtSupport::QtKitInformation::qtVersion(k)); + if (qtVersion) + params.solibSearchPath = QnxUtils::searchPaths(qtVersion); + + reportStarted(); } -void QnxDebugSupport::handleRemoteProcessStarted() +void QnxDebugSupport::stop() { - QnxAbstractRunSupport::handleRemoteProcessStarted(); - Debugger::RemoteSetupResult result; - result.success = true; - result.gdbServerPort = m_pdebugPort; - result.qmlServerPort = m_qmlPort; - toolRunner()->notifyEngineRemoteSetupFinished(result); -} - -void QnxDebugSupport::handleRemoteProcessFinished(bool success) -{ - if (state() == Inactive) - return; - - if (state() == Running) { - if (!success) - toolRunner()->notifyInferiorIll(); - - } else { - Debugger::RemoteSetupResult result; - result.success = false; - result.reason = tr("The %1 process closed unexpectedly.").arg(processExecutable()); - toolRunner()->notifyEngineRemoteSetupFinished(result); - } -} - -void QnxDebugSupport::handleDebuggingFinished() -{ - // setFinished() will kill "pdebug", but we also have to kill - // the inferior process, as invoking "kill" in gdb doesn't work - // on QNX gdb - setFinished(); - m_slog2Info->stop(); - killInferiorProcess(); -} - -QString QnxDebugSupport::processExecutable() const -{ - return m_useCppDebugger? QLatin1String(Constants::QNX_DEBUG_EXECUTABLE) : m_runnable.executable; -} - -void QnxDebugSupport::killInferiorProcess() -{ - device()->signalOperation()->killProcess(m_runnable.executable); -} - -void QnxDebugSupport::handleProgressReport(const QString &progressOutput) -{ - toolRunner()->showMessage(progressOutput + QLatin1Char('\n'), Debugger::AppStuff); -} - -void QnxDebugSupport::handleRemoteOutput(const QByteArray &output) -{ - QTC_ASSERT(state() == Inactive || state() == Running, return); - toolRunner()->showMessage(QString::fromUtf8(output), Debugger::AppOutput); -} - -void QnxDebugSupport::handleError(const QString &error) -{ - if (state() == Running) { - toolRunner()->showMessage(error, Debugger::AppError); - toolRunner()->notifyInferiorIll(); - } else if (state() != Inactive) { - setFinished(); - Debugger::RemoteSetupResult result; - result.success = false; - result.reason = tr("Initial setup failed: %1").arg(error); - toolRunner()->notifyEngineRemoteSetupFinished(result); - } -} - -void QnxDebugSupport::printMissingWarning() -{ - toolRunner()->showMessage(tr("Warning: \"slog2info\" is not found " - "on the device, debug output not available."), Debugger::AppError); -} - -void QnxDebugSupport::handleApplicationOutput(const QString &msg, Utils::OutputFormat outputFormat) -{ - Q_UNUSED(outputFormat); - toolRunner()->showMessage(msg, Debugger::AppOutput); -} - -Debugger::DebuggerRunTool *QnxDebugSupport::toolRunner() -{ - return qobject_cast(runControl()->toolRunner()); + // We have to kill the inferior process, as invoking "kill" in + // gdb doesn't work on QNX gdb. + auto stdRunnable = runnable().as(); + device()->signalOperation()->killProcess(stdRunnable.executable); } } // namespace Internal diff --git a/src/plugins/qnx/qnxdebugsupport.h b/src/plugins/qnx/qnxdebugsupport.h index 5e198a2469e..e408f703f3a 100644 --- a/src/plugins/qnx/qnxdebugsupport.h +++ b/src/plugins/qnx/qnxdebugsupport.h @@ -25,55 +25,21 @@ #pragma once -#include "qnxabstractrunsupport.h" - -#include - -#include - -namespace Debugger { class DebuggerRunTool; } +#include namespace Qnx { namespace Internal { -class Slog2InfoRunner; - -class QnxDebugSupport : public QnxAbstractRunSupport +class QnxDebugSupport : public Debugger::DebuggerRunTool { Q_OBJECT public: explicit QnxDebugSupport(ProjectExplorer::RunControl *runControl); - void handleDebuggingFinished(); - private: - void handleAdapterSetupRequested() override; - - void handleRemoteProcessStarted() override; - void handleRemoteProcessFinished(bool success) override; - void handleProgressReport(const QString &progressOutput) override; - void handleRemoteOutput(const QByteArray &output) override; - void handleError(const QString &error) override; - - void printMissingWarning(); - void handleApplicationOutput(const QString &msg, Utils::OutputFormat outputFormat); - - void startExecution() override; - - Debugger::DebuggerRunTool *toolRunner(); - QString processExecutable() const; - - void killInferiorProcess(); - - ProjectExplorer::StandardRunnable m_runnable; - Slog2InfoRunner *m_slog2Info; - - Utils::Port m_pdebugPort; - Utils::Port m_qmlPort; - - bool m_useCppDebugger; - bool m_useQmlDebugger; + void start() override; + void stop() override; }; } // namespace Internal diff --git a/src/plugins/qnx/qnxruncontrol.cpp b/src/plugins/qnx/qnxruncontrol.cpp deleted file mode 100644 index 926274c5010..00000000000 --- a/src/plugins/qnx/qnxruncontrol.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 BlackBerry Limited. All rights reserved. -** Contact: KDAB (info@kdab.com) -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "qnxruncontrol.h" -#include "qnxdevice.h" -#include "qnxrunconfiguration.h" -#include "slog2inforunner.h" - -#include -#include -#include - -using namespace ProjectExplorer; -using namespace Utils; - -namespace Qnx { -namespace Internal { - -QnxRunControl::QnxRunControl(RunConfiguration *runConfig) - : RunControl(runConfig, ProjectExplorer::Constants::NORMAL_RUN_MODE) - , m_slog2Info(0) -{ - IDevice::ConstPtr dev = DeviceKitInformation::device(runConfig->target()->kit()); - QnxDevice::ConstPtr qnxDevice = dev.dynamicCast(); - - QnxRunConfiguration *qnxRunConfig = qobject_cast(runConfig); - QTC_CHECK(qnxRunConfig); - - const QString applicationId = FileName::fromString(qnxRunConfig->remoteExecutableFilePath()).fileName(); - m_slog2Info = new Slog2InfoRunner(applicationId, qnxDevice, this); - connect(m_slog2Info, &Slog2InfoRunner::output, - this, static_cast(&RunControl::appendMessage)); - connect(this, &RunControl::started, m_slog2Info, &Slog2InfoRunner::start); - if (qnxDevice->qnxVersion() > 0x060500) - connect(m_slog2Info, &Slog2InfoRunner::commandMissing, this, &QnxRunControl::printMissingWarning); -} - -void QnxRunControl::stop() -{ - m_slog2Info->stop(); - RunControl::stop(); -} - -void QnxRunControl::printMissingWarning() -{ - appendMessage(tr("Warning: \"slog2info\" is not found on the device, debug output not available."), ErrorMessageFormat); -} - -} // namespace Internal -} // namespace Qnx diff --git a/src/plugins/qnx/qnxruncontrol.h b/src/plugins/qnx/qnxruncontrol.h deleted file mode 100644 index a447682101d..00000000000 --- a/src/plugins/qnx/qnxruncontrol.h +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 BlackBerry Limited. All rights reserved. -** Contact: KDAB (info@kdab.com) -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include - -namespace Qnx { -namespace Internal { - -class Slog2InfoRunner; - -class QnxRunControl : public ProjectExplorer::RunControl -{ - Q_OBJECT -public: - explicit QnxRunControl(ProjectExplorer::RunConfiguration *runConfig); - - void stop() override; - -private: - void printMissingWarning(); - - Slog2InfoRunner *m_slog2Info; -}; - -} // namespace Internal -} // namespace Qnx diff --git a/src/plugins/qnx/qnxruncontrolfactory.cpp b/src/plugins/qnx/qnxruncontrolfactory.cpp index 36dfe09766c..a1e60198027 100644 --- a/src/plugins/qnx/qnxruncontrolfactory.cpp +++ b/src/plugins/qnx/qnxruncontrolfactory.cpp @@ -30,7 +30,7 @@ #include "qnxdevice.h" #include "qnxanalyzesupport.h" #include "qnxqtversion.h" -#include "qnxruncontrol.h" +#include "slog2inforunner.h" #include "qnxutils.h" #include @@ -53,38 +53,6 @@ using namespace ProjectExplorer; namespace Qnx { namespace Internal { -static DebuggerStartParameters createDebuggerStartParameters(QnxRunConfiguration *runConfig) -{ - DebuggerStartParameters params; - Target *target = runConfig->target(); - Kit *k = target->kit(); - - const IDevice::ConstPtr device = DeviceKitInformation::device(k); - if (device.isNull()) - return params; - - params.startMode = AttachToRemoteServer; - params.useCtrlCStub = true; - params.inferior.executable = runConfig->remoteExecutableFilePath(); - params.symbolFile = runConfig->localExecutableFilePath(); - params.remoteChannel = device->sshParameters().host + QLatin1String(":-1"); - params.remoteSetupNeeded = true; - params.closeMode = KillAtClose; - params.inferior.commandLineArguments = runConfig->arguments(); - - auto aspect = runConfig->extraAspect(); - if (aspect->useQmlDebugger()) { - params.qmlServer.host = device->sshParameters().host; - params.qmlServer.port = Utils::Port(); // QML port is handed out later - } - - auto qtVersion = dynamic_cast(QtSupport::QtKitInformation::qtVersion(k)); - if (qtVersion) - params.solibSearchPath = QnxUtils::searchPaths(qtVersion); - - return params; -} - QnxRunControlFactory::QnxRunControlFactory(QObject *parent) : IRunControlFactory(parent) { @@ -108,48 +76,28 @@ bool QnxRunControlFactory::canRun(RunConfiguration *runConfiguration, Core::Id m if (dev.isNull()) return false; - if (mode == ProjectExplorer::Constants::DEBUG_RUN_MODE - || mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - auto aspect = runConfiguration->extraAspect(); - int portsUsed = aspect ? aspect->portsUsedByDebugger() : 0; - return portsUsed <= dev->freePorts().count(); - } - return true; } RunControl *QnxRunControlFactory::create(RunConfiguration *runConfig, Core::Id mode, QString *) { QTC_ASSERT(canRun(runConfig, mode), return 0); - auto rc = qobject_cast(runConfig); - QTC_ASSERT(rc, return 0); if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE) { - auto runControl = new QnxRunControl(rc); + auto runControl = new RunControl(runConfig, mode); (void) new SimpleTargetRunner(runControl); return runControl; } if (mode == ProjectExplorer::Constants::DEBUG_RUN_MODE) { - const DebuggerStartParameters params = createDebuggerStartParameters(rc); auto runControl = new RunControl(runConfig, mode); - // (void) new DebuggerRunTool(runControl, params, errorMessage); FIXME (void) new QnxDebugSupport(runControl); return runControl; } if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - Kit *kit = runConfig->target()->kit(); - const IDevice::ConstPtr device = DeviceKitInformation::device(kit); - if (device.isNull()) - return 0; - RunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, mode); - QTC_ASSERT(runControl, return 0); - AnalyzerConnection connection; - connection.connParams = device->sshParameters(); - connection.analyzerHost = connection.connParams.host; - connection.analyzerPort = Utils::Port(connection.connParams.port); - runControl->setConnection(connection); + RunControl *runControl = new RunControl(runConfig, mode); + runControl->createWorker(mode); (void) new QnxAnalyzeSupport(runControl); return runControl; } diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index 7b5f0f38bf4..3bde0d43010 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -25,7 +25,9 @@ #include "slog2inforunner.h" +#include "qnxdevice.h" #include "qnxdeviceprocess.h" +#include "qnxrunconfiguration.h" #include #include @@ -33,28 +35,33 @@ #include using namespace ProjectExplorer; +using namespace Utils; namespace Qnx { namespace Internal { -Slog2InfoRunner::Slog2InfoRunner(const QString &applicationId, - const RemoteLinux::LinuxDevice::ConstPtr &device, QObject *parent) - : QObject(parent) - , m_applicationId(applicationId) - , m_found(false) - , m_currentLogs(false) +Slog2InfoRunner::Slog2InfoRunner(RunControl *runControl) + : RunWorker(runControl) { + auto qnxRunConfig = qobject_cast(runControl->runConfiguration()); + QTC_ASSERT(qnxRunConfig, return); + m_applicationId = FileName::fromString(qnxRunConfig->remoteExecutableFilePath()).fileName(); +} + +void Slog2InfoRunner::printMissingWarning() +{ + appendMessage(tr("Warning: \"slog2info\" is not found on the device, debug output not available."), ErrorMessageFormat); // See QTCREATORBUG-10712 for details. // We need to limit length of ApplicationId to 63 otherwise it would not match one in slog2info. m_applicationId.truncate(63); - m_testProcess = new QnxDeviceProcess(device, this); + m_testProcess = new QnxDeviceProcess(device(), this); connect(m_testProcess, &DeviceProcess::finished, this, &Slog2InfoRunner::handleTestProcessCompleted); - m_launchDateTimeProcess = new SshDeviceProcess(device, this); + m_launchDateTimeProcess = new SshDeviceProcess(device(), this); connect(m_launchDateTimeProcess, &DeviceProcess::finished, this, &Slog2InfoRunner::launchSlog2Info); - m_logProcess = new QnxDeviceProcess(device, this); + m_logProcess = new QnxDeviceProcess(device(), this); connect(m_logProcess, &DeviceProcess::readyReadStandardOutput, this, &Slog2InfoRunner::readLogStandardOutput); connect(m_logProcess, &DeviceProcess::readyReadStandardError, this, &Slog2InfoRunner::readLogStandardError); connect(m_logProcess, &DeviceProcess::error, this, &Slog2InfoRunner::handleLogError); @@ -88,10 +95,14 @@ bool Slog2InfoRunner::commandFound() const void Slog2InfoRunner::handleTestProcessCompleted() { m_found = (m_testProcess->exitCode() == 0); - if (m_found) + if (m_found) { readLaunchTime(); - else - emit commandMissing(); + } else { + QnxDevice::ConstPtr qnxDevice = device().dynamicCast(); + if (qnxDevice->qnxVersion() > 0x060500) { + printMissingWarning(); + } + } } void Slog2InfoRunner::readLaunchTime() @@ -174,18 +185,18 @@ void Slog2InfoRunner::processLogLine(const QString &line) if (bufferName == QLatin1String("default") && bufferId == 8900) return; - emit output(regexp.cap(6).trimmed() + QLatin1Char('\n'), Utils::StdOutFormat); + appendMessage(regexp.cap(6).trimmed() + '\n', Utils::StdOutFormat); } void Slog2InfoRunner::readLogStandardError() { - const QString message = QString::fromLatin1(m_logProcess->readAllStandardError()); - emit output(message, Utils::StdErrFormat); + appendMessage(QString::fromLatin1(m_logProcess->readAllStandardError()), Utils::StdErrFormat); } void Slog2InfoRunner::handleLogError() { - emit output(tr("Cannot show slog2info output. Error: %1").arg(m_logProcess->errorString()), Utils::StdErrFormat); + appendMessage(tr("Cannot show slog2info output. Error: %1") + .arg(m_logProcess->errorString()), Utils::StdErrFormat); } } // namespace Internal diff --git a/src/plugins/qnx/slog2inforunner.h b/src/plugins/qnx/slog2inforunner.h index 4e08b5f950e..048915baac9 100644 --- a/src/plugins/qnx/slog2inforunner.h +++ b/src/plugins/qnx/slog2inforunner.h @@ -27,6 +27,7 @@ #include +#include #include #include @@ -38,26 +39,23 @@ namespace ProjectExplorer { class SshDeviceProcess; } namespace Qnx { namespace Internal { -class Slog2InfoRunner : public QObject +class Slog2InfoRunner : public ProjectExplorer::RunWorker { Q_OBJECT public: - explicit Slog2InfoRunner(const QString &applicationId, const RemoteLinux::LinuxDevice::ConstPtr &device, QObject *parent = 0); + explicit Slog2InfoRunner(ProjectExplorer::RunControl *runControl); - void stop(); + void start() override; + void stop() override; bool commandFound() const; -public slots: - void start(); - signals: void commandMissing(); void started(); void finished(); - void output(const QString &msg, Utils::OutputFormat format); -private slots: +private: void handleTestProcessCompleted(); void launchSlog2Info(); @@ -65,22 +63,21 @@ private slots: void readLogStandardError(); void handleLogError(); -private: + void printMissingWarning(); void readLaunchTime(); void processLog(bool force); void processLogLine(const QString &line); QString m_applicationId; - bool m_found; - QDateTime m_launchDateTime; - bool m_currentLogs; + bool m_found = false; + bool m_currentLogs = false; QString m_remainingData; - ProjectExplorer::SshDeviceProcess *m_launchDateTimeProcess; - ProjectExplorer::SshDeviceProcess *m_testProcess; - ProjectExplorer::SshDeviceProcess *m_logProcess; + ProjectExplorer::SshDeviceProcess *m_launchDateTimeProcess = nullptr; + ProjectExplorer::SshDeviceProcess *m_testProcess = nullptr; + ProjectExplorer::SshDeviceProcess *m_logProcess = nullptr; }; } // namespace Internal diff --git a/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp b/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp index 4dc313d5e6d..15521b8ddbb 100644 --- a/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp @@ -25,89 +25,34 @@ #include "abstractremotelinuxrunsupport.h" -#include #include #include #include #include #include +#include + +#include using namespace ProjectExplorer; using namespace Utils; namespace RemoteLinux { -namespace Internal { -class AbstractRemoteLinuxRunSupportPrivate +// FifoGatherer + +FifoGatherer::FifoGatherer(RunControl *runControl) + : RunWorker(runControl) { -public: - ApplicationLauncher launcher; - DeviceUsedPortsGatherer portsGatherer; - ApplicationLauncher fifoCreator; - PortList portList; - QString fifo; - bool usesFifo = false; -}; + setDisplayName("FifoGatherer"); +} -} // namespace Internal - -using namespace Internal; - -AbstractRemoteLinuxRunSupport::AbstractRemoteLinuxRunSupport(RunControl *runControl) - : TargetRunner(runControl), - d(new AbstractRemoteLinuxRunSupportPrivate) +FifoGatherer::~FifoGatherer() { } -AbstractRemoteLinuxRunSupport::~AbstractRemoteLinuxRunSupport() -{ - delete d; -} - -ApplicationLauncher *AbstractRemoteLinuxRunSupport::applicationLauncher() -{ - return &d->launcher; -} - -void AbstractRemoteLinuxRunSupport::setUsesFifo(bool on) -{ - d->usesFifo = on; -} - -Port AbstractRemoteLinuxRunSupport::findPort() const -{ - return d->portsGatherer.getNextFreePort(&d->portList); -} - -QString AbstractRemoteLinuxRunSupport::fifo() const -{ - return d->fifo; -} - -void AbstractRemoteLinuxRunSupport::prepare() -{ - if (d->usesFifo) - createRemoteFifo(); - else - startPortsGathering(); -} - -void AbstractRemoteLinuxRunSupport::startPortsGathering() -{ - appendMessage(tr("Checking available ports...") + '\n', NormalMessageFormat); - connect(&d->portsGatherer, &DeviceUsedPortsGatherer::error, this, [&](const QString &msg) { - reportFailure(msg); - }); - connect(&d->portsGatherer, &DeviceUsedPortsGatherer::portListReady, this, [&] { - d->portList = device()->freePorts(); - //appendMessage(tr("Found %1 free ports").arg(d->portList.count()), NormalMessageFormat); - reportSuccess(); - }); - d->portsGatherer.start(device()); -} - -void AbstractRemoteLinuxRunSupport::createRemoteFifo() +void FifoGatherer::start() { appendMessage(tr("Creating remote socket...") + '\n', NormalMessageFormat); @@ -120,77 +65,35 @@ void AbstractRemoteLinuxRunSupport::createRemoteFifo() QSharedPointer output(new QByteArray); QSharedPointer errors(new QByteArray); - connect(&d->fifoCreator, &ApplicationLauncher::finished, + connect(&m_fifoCreator, &ApplicationLauncher::finished, this, [this, output, errors](bool success) { if (!success) { reportFailure(QString("Failed to create fifo: %1").arg(QLatin1String(*errors))); } else { - d->fifo = QString::fromLatin1(*output); - //appendMessage(tr("Created fifo").arg(d->fifo), NormalMessageFormat); - reportSuccess(); + m_fifo = QString::fromLatin1(*output); + appendMessage(tr("Created fifo: %1").arg(m_fifo), NormalMessageFormat); + reportStarted(); } }); - connect(&d->fifoCreator, &ApplicationLauncher::remoteStdout, + connect(&m_fifoCreator, &ApplicationLauncher::remoteStdout, this, [output](const QByteArray &data) { output->append(data); }); - connect(&d->fifoCreator, &ApplicationLauncher::remoteStderr, - this, [errors](const QByteArray &data) { - errors->append(data); + connect(&m_fifoCreator, &ApplicationLauncher::remoteStderr, + this, [this, errors](const QByteArray &) { + reportFailure(); +// errors->append(data); }); - d->fifoCreator.start(r, device()); + m_fifoCreator.start(r, device()); } -void AbstractRemoteLinuxRunSupport::start() +void FifoGatherer::onFinished() { - connect(&d->launcher, &ApplicationLauncher::remoteStderr, - this, &AbstractRemoteLinuxRunSupport::handleRemoteErrorOutput); - connect(&d->launcher, &ApplicationLauncher::remoteStdout, - this, &AbstractRemoteLinuxRunSupport::handleRemoteOutput); - connect(&d->launcher, &ApplicationLauncher::finished, - this, &AbstractRemoteLinuxRunSupport::handleAppRunnerFinished); - connect(&d->launcher, &ApplicationLauncher::reportProgress, - this, &AbstractRemoteLinuxRunSupport::handleProgressReport); - connect(&d->launcher, &ApplicationLauncher::reportError, - this, &AbstractRemoteLinuxRunSupport::handleAppRunnerError); - connect(&d->launcher, &ApplicationLauncher::remoteProcessStarted, - this, &TargetRunner::reportSuccess); - d->launcher.start(runControl()->runnable(), device()); + m_fifoCreator.stop(); } -void AbstractRemoteLinuxRunSupport::onFinished() -{ - d->launcher.disconnect(this); - d->launcher.stop(); - d->portsGatherer.disconnect(this); -} - -void AbstractRemoteLinuxRunSupport::handleAppRunnerFinished(bool success) -{ - success ? reportStopped() : reportFailure(); -} - -void AbstractRemoteLinuxRunSupport::handleAppRunnerError(const QString &error) -{ - reportFailure(error); -} - -void AbstractRemoteLinuxRunSupport::handleRemoteOutput(const QByteArray &output) -{ - appendMessage(QString::fromUtf8(output), StdOutFormat); -} - -void AbstractRemoteLinuxRunSupport::handleRemoteErrorOutput(const QByteArray &output) -{ - appendMessage(QString::fromUtf8(output), StdErrFormat); -} - -void AbstractRemoteLinuxRunSupport::handleProgressReport(const QString &progressOutput) -{ - appendMessage(progressOutput + '\n', LogMessageFormat); -} } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/abstractremotelinuxrunsupport.h b/src/plugins/remotelinux/abstractremotelinuxrunsupport.h index a914d48ea7f..2a6be032bc5 100644 --- a/src/plugins/remotelinux/abstractremotelinuxrunsupport.h +++ b/src/plugins/remotelinux/abstractremotelinuxrunsupport.h @@ -27,46 +27,28 @@ #include "remotelinux_export.h" -#include #include -#include - namespace RemoteLinux { -namespace Internal { class AbstractRemoteLinuxRunSupportPrivate; } - -class REMOTELINUX_EXPORT AbstractRemoteLinuxRunSupport : public ProjectExplorer::TargetRunner +class REMOTELINUX_EXPORT FifoGatherer : public ProjectExplorer::RunWorker { Q_OBJECT public: - explicit AbstractRemoteLinuxRunSupport(ProjectExplorer::RunControl *runControl); - ~AbstractRemoteLinuxRunSupport(); + explicit FifoGatherer(ProjectExplorer::RunControl *runControl); + ~FifoGatherer(); - ProjectExplorer::ApplicationLauncher *applicationLauncher(); - - void setUsesFifo(bool on); - - Utils::Port findPort() const; - QString fifo() const; + QString fifo() const { return m_fifo; } private: - void prepare() override; void start() override; void onFinished() override; void createRemoteFifo(); - void startPortsGathering(); - void handleAppRunnerError(const QString &error); - void handleRemoteOutput(const QByteArray &output); - void handleRemoteErrorOutput(const QByteArray &output); - void handleAppRunnerFinished(bool success); - void handleProgressReport(const QString &progressOutput); - void handleAdapterSetupDone(); - - Internal::AbstractRemoteLinuxRunSupportPrivate * const d; + ProjectExplorer::ApplicationLauncher m_fifoCreator; + QString m_fifo; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp b/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp index 4652734e2f9..a2519b7b67d 100644 --- a/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp +++ b/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp @@ -1,210 +1,172 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ +///**************************************************************************** +//** +//** Copyright (C) 2016 The Qt Company Ltd. +//** Contact: https://www.qt.io/licensing/ +//** +//** This file is part of Qt Creator. +//** +//** Commercial License Usage +//** Licensees holding valid commercial Qt licenses may use this file in +//** accordance with the commercial license agreement provided with the +//** Software or, alternatively, in accordance with the terms contained in +//** a written agreement between you and The Qt Company. For licensing terms +//** and conditions see https://www.qt.io/terms-conditions. For further +//** information use the contact form at https://www.qt.io/contact-us. +//** +//** GNU General Public License Usage +//** Alternatively, this file may be used under the terms of the GNU +//** General Public License version 3 as published by the Free Software +//** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +//** included in the packaging of this file. Please review the following +//** information to ensure the GNU General Public License requirements will +//** be met: https://www.gnu.org/licenses/gpl-3.0.html. +//** +//****************************************************************************/ -#include "remotelinuxanalyzesupport.h" +//#include "remotelinuxanalyzesupport.h" -#include "remotelinuxrunconfiguration.h" +//#include "remotelinuxrunconfiguration.h" -#include -#include -#include -#include -#include -#include +//#include +//#include +//#include +//#include +//#include +//#include -#include -#include -#include -#include +//#include +//#include +//#include +//#include -#include +//#include -using namespace QSsh; -using namespace ProjectExplorer; -using namespace Utils; +//using namespace QSsh; +//using namespace ProjectExplorer; +//using namespace Utils; -namespace RemoteLinux { -namespace Internal { +//namespace RemoteLinux { +//namespace Internal { -class RemoteLinuxAnalyzeSupportPrivate -{ -public: - RemoteLinuxAnalyzeSupportPrivate(RunControl *runControl) - { - if (runControl->runMode() == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { - usesFifo = true; - RunConfiguration *runConfiguration = runControl->runConfiguration(); - QTC_ASSERT(runConfiguration, return); - IRunConfigurationAspect *perfAspect = - runConfiguration->extraAspect("Analyzer.Perf.Settings"); - QTC_ASSERT(perfAspect, return); - perfRecordArguments = - perfAspect->currentSettings()->property("perfRecordArguments").toStringList() - .join(' '); - } - } +//const char RemoteLinuxAnalyzeSupportWorkerId[] = "RemoteLinux.AnalyzeSupportWorker"; - Utils::Port qmlPort; - QString remoteFifo; - QString perfRecordArguments; +//class RemoteLinuxAnalyzeSupportPrivate +//{ +//public: +// RemoteLinuxAnalyzeSupportPrivate(RunControl *runControl) +// { +// bool isPerf = runControl->runMode() == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE; +// needFifo = isPerf; +// if (needFifo) { +// RunConfiguration *runConfiguration = runControl->runConfiguration(); +// QTC_ASSERT(runConfiguration, return); +// IRunConfigurationAspect *perfAspect = +// runConfiguration->extraAspect("Analyzer.Perf.Settings"); +// QTC_ASSERT(perfAspect, return); +// perfRecordArguments = +// perfAspect->currentSettings()->property("perfRecordArguments").toStringList() +// .join(' '); +// } +// } - ApplicationLauncher outputGatherer; - QmlDebug::QmlOutputParser outputParser; - bool usesFifo = false; -}; +// Utils::Port qmlPort; +// QString remoteFifo; +// QString perfRecordArguments; -} // namespace Internal +// ApplicationLauncher outputGatherer; +// QmlDebug::QmlOutputParser outputParser; +// bool needFifo = false; +// bool needPort = false; +//}; -using namespace Internal; +//} // namespace Internal -RemoteLinuxAnalyzeSupport::RemoteLinuxAnalyzeSupport(RunControl *runControl) - : ToolRunner(runControl), - d(new RemoteLinuxAnalyzeSupportPrivate(runControl)) -{ - connect(&d->outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, - this, &RemoteLinuxAnalyzeSupport::remoteIsRunning); - targetRunner()->setUsesFifo(runControl->runMode() == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE); -} +//using namespace Internal; -RemoteLinuxAnalyzeSupport::~RemoteLinuxAnalyzeSupport() -{ - delete d; -} +//RemoteLinuxAnalyzeSupport::RemoteLinuxAnalyzeSupport(RunControl *runControl) +// : ToolRunner(runControl), +// d(new RemoteLinuxAnalyzeSupportPrivate(runControl)) +//{ +// setId(RemoteLinuxAnalyzeSupportWorkerId); -void RemoteLinuxAnalyzeSupport::showMessage(const QString &msg, Utils::OutputFormat format) -{ - appendMessage(msg, format); - d->outputParser.processOutput(msg); -} +// connect(&d->outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, +// this, &RemoteLinuxAnalyzeSupport::remoteIsRunning); -void RemoteLinuxAnalyzeSupport::start() -{ - const Core::Id runMode = runControl()->runMode(); - if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - d->qmlPort = targetRunner()->findPort(); - if (!d->qmlPort.isValid()) { - reportFailure(tr("Not enough free ports on device for profiling.")); - return; - } - } else if (runMode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { - d->remoteFifo = targetRunner()->fifo(); - if (d->remoteFifo.isEmpty()) { - reportFailure(tr("FIFO for profiling data could not be created.")); - return; - } - } +// if (d->needFifo) +// addDependency(FifoCreatorWorkerId); +// if (d->needPort) +// addDependency(PortsGathererWorkerId); +//} - ApplicationLauncher *runner = targetRunner()->applicationLauncher(); - connect(runner, &ApplicationLauncher::remoteStderr, - this, &RemoteLinuxAnalyzeSupport::handleRemoteErrorOutput); - connect(runner, &ApplicationLauncher::remoteStdout, - this, &RemoteLinuxAnalyzeSupport::handleRemoteOutput); - connect(runner, &ApplicationLauncher::remoteProcessStarted, - this, &RemoteLinuxAnalyzeSupport::handleRemoteProcessStarted); - connect(runner, &ApplicationLauncher::finished, - this, &RemoteLinuxAnalyzeSupport::handleAppRunnerFinished); - connect(runner, &ApplicationLauncher::reportProgress, - this, &RemoteLinuxAnalyzeSupport::handleProgressReport); - connect(runner, &ApplicationLauncher::reportError, - this, &RemoteLinuxAnalyzeSupport::handleAppRunnerError); +//RemoteLinuxAnalyzeSupport::~RemoteLinuxAnalyzeSupport() +//{ +// delete d; +//} - auto r = runControl()->runnable().as(); +////void RemoteLinuxAnalyzeSupport::showMessage(const QString &msg, Utils::OutputFormat format) +////{ +//// appendMessage(msg, format); +//// d->outputParser.processOutput(msg); +////} - if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - if (!r.commandLineArguments.isEmpty()) - r.commandLineArguments.append(QLatin1Char(' ')); - r.commandLineArguments += QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, - d->qmlPort); - } else if (runMode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { - r.commandLineArguments = QLatin1String("-c 'perf record -o - ") + d->perfRecordArguments - + QLatin1String(" -- ") + r.executable + QLatin1String(" ") - + r.commandLineArguments + QLatin1String(" > ") + d->remoteFifo - + QLatin1String("'"); - r.executable = QLatin1String("sh"); +//void RemoteLinuxAnalyzeSupport::start() +//{ +// if (d->needPort) { +// RunWorker *worker = qobject_cast(); +// QTC_ASSERT(worker, reportFailure(); return); +// runControl()->worker(PortsGathererWorkerId)->result(); +// d->qmlPort = targetRunner()->findPort(); +// if (!d->qmlPort.isValid()) { +// reportFailure(tr("Not enough free ports on device for profiling.")); +// return; +// } +// } else if (runMode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { +// d->remoteFifo = targetRunner()->fifo(); +// if (d->remoteFifo.isEmpty()) { +// reportFailure(tr("FIFO for profiling data could not be created.")); +// return; +// } +// } - connect(&d->outputGatherer, SIGNAL(remoteStdout(QByteArray)), - runControl(), SIGNAL(analyzePerfOutput(QByteArray))); - connect(&d->outputGatherer, SIGNAL(finished(bool)), - runControl(), SIGNAL(perfFinished())); +// ApplicationLauncher *runner = targetRunner()->applicationLauncher(); - StandardRunnable outputRunner; - outputRunner.executable = QLatin1String("sh"); - outputRunner.commandLineArguments = - QString::fromLatin1("-c 'cat %1 && rm -r `dirname %1`'").arg(d->remoteFifo); - d->outputGatherer.start(outputRunner, device()); - remoteIsRunning(); - } - runner->start(r, device()); -} +// auto r = runControl()->runnable().as(); -void RemoteLinuxAnalyzeSupport::handleAppRunnerError(const QString &error) -{ - showMessage(error, Utils::ErrorMessageFormat); - reportFailure(error); -} +// if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { +// if (!r.commandLineArguments.isEmpty()) +// r.commandLineArguments.append(QLatin1Char(' ')); +// r.commandLineArguments += QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, +// d->qmlPort); +// } else if (runMode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { +// r.commandLineArguments = QLatin1String("-c 'perf record -o - ") + d->perfRecordArguments +// + QLatin1String(" -- ") + r.executable + QLatin1String(" ") +// + r.commandLineArguments + QLatin1String(" > ") + d->remoteFifo +// + QLatin1String("'"); +// r.executable = QLatin1String("sh"); -void RemoteLinuxAnalyzeSupport::handleAppRunnerFinished(bool success) -{ - // reset needs to be called first to ensure that the correct state is set. - if (!success) - showMessage(tr("Failure running remote process."), Utils::NormalMessageFormat); - runControl()->notifyRemoteFinished(); -} +// connect(&d->outputGatherer, SIGNAL(remoteStdout(QByteArray)), +// runControl(), SIGNAL(analyzePerfOutput(QByteArray))); +// connect(&d->outputGatherer, SIGNAL(finished(bool)), +// runControl(), SIGNAL(perfFinished())); -void RemoteLinuxAnalyzeSupport::remoteIsRunning() -{ - runControl()->notifyRemoteSetupDone(d->qmlPort); -} +// StandardRunnable outputRunner; +// outputRunner.executable = QLatin1String("sh"); +// outputRunner.commandLineArguments = +// QString::fromLatin1("-c 'cat %1 && rm -r `dirname %1`'").arg(d->remoteFifo); +// d->outputGatherer.start(outputRunner, device()); +// remoteIsRunning(); +// } +// runner->start(r, device()); +//} -AbstractRemoteLinuxRunSupport *RemoteLinuxAnalyzeSupport::targetRunner() const -{ - return qobject_cast(runControl()->targetRunner()); -} +//void RemoteLinuxAnalyzeSupport::remoteIsRunning() +//{ +// runControl()->notifyRemoteSetupDone(d->qmlPort); +//} -void RemoteLinuxAnalyzeSupport::handleRemoteOutput(const QByteArray &output) -{ - showMessage(QString::fromUtf8(output), Utils::StdOutFormat); -} +//AbstractRemoteLinuxRunSupport *RemoteLinuxAnalyzeSupport::targetRunner() const +//{ +// return qobject_cast(runControl()->targetRunner()); +//} -void RemoteLinuxAnalyzeSupport::handleRemoteErrorOutput(const QByteArray &output) -{ - showMessage(QString::fromUtf8(output), Utils::StdErrFormat); -} - -void RemoteLinuxAnalyzeSupport::handleProgressReport(const QString &progressOutput) -{ - showMessage(progressOutput + QLatin1Char('\n'), Utils::NormalMessageFormat); -} - -void RemoteLinuxAnalyzeSupport::handleAdapterSetupFailed(const QString &error) -{ - showMessage(tr("Initial setup failed: %1").arg(error), Utils::NormalMessageFormat); -} - -void RemoteLinuxAnalyzeSupport::handleRemoteProcessStarted() -{ -} - -} // namespace RemoteLinux +//} // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxanalyzesupport.h b/src/plugins/remotelinux/remotelinuxanalyzesupport.h index f125deba914..e1cefa6f97e 100644 --- a/src/plugins/remotelinux/remotelinuxanalyzesupport.h +++ b/src/plugins/remotelinux/remotelinuxanalyzesupport.h @@ -1,67 +1,54 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ +///**************************************************************************** +//** +//** Copyright (C) 2016 The Qt Company Ltd. +//** Contact: https://www.qt.io/licensing/ +//** +//** This file is part of Qt Creator. +//** +//** Commercial License Usage +//** Licensees holding valid commercial Qt licenses may use this file in +//** accordance with the commercial license agreement provided with the +//** Software or, alternatively, in accordance with the terms contained in +//** a written agreement between you and The Qt Company. For licensing terms +//** and conditions see https://www.qt.io/terms-conditions. For further +//** information use the contact form at https://www.qt.io/contact-us. +//** +//** GNU General Public License Usage +//** Alternatively, this file may be used under the terms of the GNU +//** General Public License version 3 as published by the Free Software +//** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +//** included in the packaging of this file. Please review the following +//** information to ensure the GNU General Public License requirements will +//** be met: https://www.gnu.org/licenses/gpl-3.0.html. +//** +//****************************************************************************/ -#pragma once +//#pragma once -#include "abstractremotelinuxrunsupport.h" +//#include "abstractremotelinuxrunsupport.h" -#include -#include +//#include +//#include -#include +//#include -namespace RemoteLinux { +//namespace RemoteLinux { -namespace Internal { class RemoteLinuxAnalyzeSupportPrivate; } +//namespace Internal { class RemoteLinuxAnalyzeSupportPrivate; } -class REMOTELINUX_EXPORT RemoteLinuxAnalyzeSupport : public ProjectExplorer::ToolRunner -{ - Q_OBJECT -public: - RemoteLinuxAnalyzeSupport(ProjectExplorer::RunControl *runControl); - ~RemoteLinuxAnalyzeSupport() override; +//class REMOTELINUX_EXPORT RemoteLinuxAnalyzeSupport : public ProjectExplorer::RunWorker +//{ +// Q_OBJECT +//public: +// RemoteLinuxAnalyzeSupport(ProjectExplorer::RunControl *runControl); +// ~RemoteLinuxAnalyzeSupport() override; -private: - void start() override; - void handleAdapterSetupFailed(const QString &error); +//private: +// void start() override; - void handleRemoteSetupRequested(); - void handleAppRunnerError(const QString &error); - void handleRemoteOutput(const QByteArray &output); - void handleRemoteErrorOutput(const QByteArray &output); - void handleAppRunnerFinished(bool success); - void handleProgressReport(const QString &progressOutput); +// void remoteIsRunning(); - void handleRemoteProcessStarted(); +// Internal::RemoteLinuxAnalyzeSupportPrivate * const d; +//}; - void remoteIsRunning(); - AbstractRemoteLinuxRunSupport *targetRunner() const; - - void showMessage(const QString &, Utils::OutputFormat); - - Internal::RemoteLinuxAnalyzeSupportPrivate * const d; -}; - -} // namespace RemoteLinux +//} // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp index 9bcdc5b2079..331b5c3ad3b 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp @@ -47,10 +47,35 @@ using namespace Utils; namespace RemoteLinux { -LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl, QString *errorMessage) +LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl) : DebuggerRunTool(runControl) { - RunConfiguration *runConfig = runControl->runConfiguration(); + setDisplayName("DebugSupport"); + + auto portsGatherer = new GdbServerPortsGatherer(runControl); + portsGatherer->setUseGdbServer(isCppDebugging()); + portsGatherer->setUseQmlServer(isQmlDebugging()); + + auto gdbServer = new GdbServerRunner(runControl); + gdbServer->addDependency(portsGatherer); + + addDependency(gdbServer); +} + +LinuxDeviceDebugSupport::~LinuxDeviceDebugSupport() +{ +} + +void LinuxDeviceDebugSupport::start() +{ + auto portsGatherer = runControl()->worker(); + QTC_ASSERT(portsGatherer, reportFailure(); return); + + const QString host = device()->sshParameters().host; + const Port gdbServerPort = portsGatherer->gdbServerPort(); + const Port qmlServerPort = portsGatherer->qmlServerPort(); + + RunConfiguration *runConfig = runControl()->runConfiguration(); QString symbolFile; if (auto rlrc = qobject_cast(runConfig)) @@ -58,7 +83,7 @@ LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl, QString if (auto rlrc = qobject_cast(runConfig)) symbolFile = rlrc->localExecutableFilePath(); if (symbolFile.isEmpty()) { - *errorMessage = tr("Cannot debug: Local executable is not set."); +// *errorMessage = tr("Cannot debug: Local executable is not set."); return; } @@ -68,8 +93,10 @@ LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl, QString params.remoteSetupNeeded = false; if (isQmlDebugging()) { - params.qmlServer.host = device()->sshParameters().host; - params.qmlServer.port = Utils::Port(); // port is selected later on + params.qmlServer.host = host; + params.qmlServer.port = qmlServerPort; + params.inferior.commandLineArguments.replace("%qml_port%", + QString::number(qmlServerPort.number())); } if (isCppDebugging()) { Runnable r = runnable(); @@ -83,69 +110,14 @@ LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl, QString params.inferior.commandLineArguments.prepend( QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices)); } - params.remoteChannel = device()->sshParameters().host + ":-1"; + + params.remoteChannel = QString("%1:%2").arg(host).arg(gdbServerPort.number()); params.symbolFile = symbolFile; } setStartParameters(params); -} -LinuxDeviceDebugSupport::~LinuxDeviceDebugSupport() -{ -} - -void LinuxDeviceDebugSupport::prepare() -{ - auto targetRunner = qobject_cast(runControl()->targetRunner()); - - if (isCppDebugging()) { - m_gdbServerPort = targetRunner->findPort(); - if (!m_gdbServerPort.isValid()) { - reportFailure(tr("Not enough free ports on device for C++ debugging.")); - return; - } - } - if (isQmlDebugging()) { - m_qmlPort = targetRunner->findPort(); - if (!m_qmlPort.isValid()) { - reportFailure(tr("Not enough free ports on device for QML debugging.")); - return; - } - } - - runControl()->setRunnable(realRunnable()); - - RemoteSetupResult result; - result.success = true; - result.gdbServerPort = m_gdbServerPort; - result.qmlServerPort = m_qmlPort; - setRemoteParameters(result); - - DebuggerRunTool::prepare(); -} - -Runnable LinuxDeviceDebugSupport::realRunnable() const -{ - StandardRunnable r = runControl()->runnable().as(); - QStringList args = QtcProcess::splitArgs(r.commandLineArguments, OsTypeLinux); - QString command; - - if (isQmlDebugging()) - args.prepend(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices, m_qmlPort)); - - if (isQmlDebugging() && !isCppDebugging()) { - command = r.executable; - } else { - command = device()->debugServerPath(); - if (command.isEmpty()) - command = QLatin1String("gdbserver"); - args.clear(); - args.append(QString::fromLatin1("--multi")); - args.append(QString::fromLatin1(":%1").arg(m_gdbServerPort.number())); - } - r.executable = command; - r.commandLineArguments = QtcProcess::joinArgs(args, OsTypeLinux); - return r; + DebuggerRunTool::start(); } } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.h b/src/plugins/remotelinux/remotelinuxdebugsupport.h index 7473f05593b..d670be1b3a8 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.h +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.h @@ -36,18 +36,11 @@ class REMOTELINUX_EXPORT LinuxDeviceDebugSupport : public Debugger::DebuggerRunT Q_OBJECT public: - LinuxDeviceDebugSupport(ProjectExplorer::RunControl *runControl, - QString *errorMessage = nullptr); + LinuxDeviceDebugSupport(ProjectExplorer::RunControl *runControl); ~LinuxDeviceDebugSupport() override; -protected: - virtual ProjectExplorer::Runnable realRunnable() const; - private: - void prepare() override; - - Utils::Port m_gdbServerPort; - Utils::Port m_qmlPort; + void start() override; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp index 978bb9aa908..76911168e87 100644 --- a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp +++ b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp @@ -30,18 +30,12 @@ #include "remotelinuxcustomrunconfiguration.h" #include "remotelinuxrunconfiguration.h" -#include -#include - #include -#include -#include #include #include #include - #include #include @@ -62,7 +56,8 @@ bool RemoteLinuxRunControlFactory::canRun(RunConfiguration *runConfiguration, Co && mode != ProjectExplorer::Constants::DEBUG_RUN_MODE && mode != ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN && mode != ProjectExplorer::Constants::QML_PROFILER_RUN_MODE - && mode != ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { +// && mode != ProjectExplorer::Constants::PERFPROFILER_RUN_MODE + ) { return false; } @@ -73,34 +68,37 @@ bool RemoteLinuxRunControlFactory::canRun(RunConfiguration *runConfiguration, Co } RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Core::Id mode, - QString *errorMessage) + QString *) { QTC_ASSERT(canRun(runConfig, mode), return 0); if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE) { auto runControl = new RunControl(runConfig, mode); - (void) new AbstractRemoteLinuxRunSupport(runControl); + (void) new SimpleTargetRunner(runControl); return runControl; } if (mode == ProjectExplorer::Constants::DEBUG_RUN_MODE || mode == ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN) { auto runControl = new RunControl(runConfig, mode); - (void) new AbstractRemoteLinuxRunSupport(runControl); - (void) new LinuxDeviceDebugSupport(runControl, errorMessage); + (void) new LinuxDeviceDebugSupport(runControl); return runControl; } - if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE || - mode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { - auto runControl = Debugger::createAnalyzerRunControl(runConfig, mode); - AnalyzerConnection connection; - connection.connParams = - DeviceKitInformation::device(runConfig->target()->kit())->sshParameters(); - connection.analyzerHost = connection.connParams.host; - runControl->setConnection(connection); - (void) new AbstractRemoteLinuxRunSupport(runControl); - (void) new RemoteLinuxAnalyzeSupport(runControl); + if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE +// || mode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE + ) { + auto runControl = new RunControl(runConfig, mode); + runControl->createWorker(mode); +// AnalyzerConnection connection; +// connection.connParams = +// DeviceKitInformation::device(runConfig->target()->kit())->sshParameters(); +// connection.analyzerHost = connection.connParams.host; +// runControl->setConnection(connection); +// (void) new SimpleTargetRunner(runControl); +// (void) new PortsGatherer(runControl); +// (void) new FifoGatherer(runControl); +// (void) new RemoteLinuxAnalyzeSupport(runControl); return runControl; } diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 01aac218778..7137659025d 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -255,14 +255,11 @@ CallgrindTool::CallgrindTool(QObject *parent) QString toolTip = tr("Valgrind Function Profiler uses the " "Callgrind tool to record function calls when a program runs."); - auto rcc = [this](RunConfiguration *runConfiguration, Id mode) { - auto runControl = new RunControl(runConfiguration, mode); - (void) createRunTool(runControl); - return runControl; - }; + RunControl::registerWorkerCreator(CALLGRIND_RUN_MODE, [this](RunControl *runControl) { + return createRunTool(runControl); + }); if (!Utils::HostOsInfo::isWindowsHost()) { - Debugger::registerAction(CALLGRIND_RUN_MODE, rcc); auto action = new QAction(tr("Valgrind Function Profiler"), this); action->setToolTip(toolTip); menu->addAction(ActionManager::registerAction(action, CallgrindLocalActionId), @@ -279,7 +276,6 @@ CallgrindTool::CallgrindTool(QObject *parent) }); } - Debugger::registerAction(CALLGRIND_RUN_MODE, rcc); auto action = new QAction(tr("Valgrind Function Profiler (External Application)"), this); action->setToolTip(toolTip); menu->addAction(ActionManager::registerAction(action, CallgrindRemoteActionId), diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 4c8d421a6c3..f452a845df0 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -244,7 +244,7 @@ class MemcheckTool : public QObject public: MemcheckTool(QObject *parent); - RunControl *createRunControl(RunConfiguration *runConfiguration, Core::Id runMode); + RunWorker *createRunWorker(RunControl *runControl); private: void updateRunActions(); @@ -395,8 +395,10 @@ MemcheckTool::MemcheckTool(QObject *parent) ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER); QString toolTip = tr("Valgrind Analyze Memory uses the Memcheck tool to find memory leaks."); + RunControl::registerWorkerCreator(MEMCHECK_RUN_MODE, std::bind(&MemcheckTool::createRunWorker, this, _1)); + RunControl::registerWorkerCreator(MEMCHECK_WITH_GDB_RUN_MODE, std::bind(&MemcheckTool::createRunWorker, this, _1)); + if (!Utils::HostOsInfo::isWindowsHost()) { - Debugger::registerAction(MEMCHECK_RUN_MODE, std::bind(&MemcheckTool::createRunControl, this, _1, _2)); action = new QAction(this); action->setText(tr("Valgrind Memory Analyzer")); action->setToolTip(toolTip); @@ -414,7 +416,6 @@ MemcheckTool::MemcheckTool(QObject *parent) action->setEnabled(m_startAction->isEnabled()); }); - Debugger::registerAction(MEMCHECK_WITH_GDB_RUN_MODE, std::bind(&MemcheckTool::createRunControl, this, _1, _2)); action = new QAction(this); action->setText(tr("Valgrind Memory Analyzer with GDB")); action->setToolTip(tr("Valgrind Analyze Memory with GDB uses the " @@ -435,7 +436,6 @@ MemcheckTool::MemcheckTool(QObject *parent) }); } - Debugger::registerAction(MEMCHECK_RUN_MODE, std::bind(&MemcheckTool::createRunControl, this, _1, _2)); action = new QAction(this); action->setText(tr("Valgrind Memory Analyzer (External Application)")); action->setToolTip(toolTip); @@ -452,8 +452,8 @@ MemcheckTool::MemcheckTool(QObject *parent) return; TaskHub::clearTasks(Debugger::Constants::ANALYZERTASK_ID); Debugger::selectPerspective(MemcheckPerspectiveId); - RunControl *rc = createRunControl(runConfig, MEMCHECK_RUN_MODE); - QTC_ASSERT(rc, return); + RunControl *rc = new RunControl(runConfig, MEMCHECK_RUN_MODE); + rc->createWorker(MEMCHECK_RUN_MODE); const auto runnable = dlg.runnable(); rc->setRunnable(runnable); AnalyzerConnection connection; @@ -560,14 +560,14 @@ void MemcheckTool::maybeActiveRunConfigurationChanged() updateFromSettings(); } -RunControl *MemcheckTool::createRunControl(RunConfiguration *runConfiguration, Core::Id runMode) +RunWorker *MemcheckTool::createRunWorker(RunControl *runControl) { - m_errorModel.setRelevantFrameFinder(makeFrameFinder(runConfiguration - ? runConfiguration->target()->project()->files(Project::AllFiles) : QStringList())); + RunConfiguration *runConfig = runControl->runConfiguration(); + m_errorModel.setRelevantFrameFinder(makeFrameFinder(runConfig + ? runConfig->target()->project()->files(Project::AllFiles) : QStringList())); - auto runControl = new RunControl(runConfiguration, runMode); MemcheckToolRunner *runTool = 0; - if (runMode == MEMCHECK_RUN_MODE) + if (runControl->runMode() == MEMCHECK_RUN_MODE) runTool = new MemcheckToolRunner(runControl); else runTool = new MemcheckWithGdbToolRunner(runControl); @@ -583,7 +583,7 @@ RunControl *MemcheckTool::createRunControl(RunConfiguration *runConfiguration, C m_toolBusy = true; updateRunActions(); - return runControl; + return runTool; } void MemcheckTool::engineStarting(const MemcheckToolRunner *runTool) @@ -739,7 +739,9 @@ public: RunControl *create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage) override { Q_UNUSED(errorMessage); - return m_tool->createRunControl(runConfiguration, mode); + auto runControl = new RunControl(runConfiguration, mode); + runControl->createWorker(mode); + return runControl; } // Do not create an aspect, let the Callgrind tool create one and use that, too. diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index a10e709b3aa..c2df034ecf2 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -54,7 +54,7 @@ namespace Valgrind { namespace Internal { ValgrindToolRunner::ValgrindToolRunner(RunControl *runControl) - : ToolRunner(runControl) + : RunWorker(runControl) { runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); runControl->setSupportsReRunning(false); @@ -102,7 +102,7 @@ void ValgrindToolRunner::start() return; } - reportSuccess(); + reportStarted(); } void ValgrindToolRunner::stop() @@ -160,7 +160,7 @@ void ValgrindToolRunner::runnerFinished() disconnect(runner(), &ValgrindRunner::finished, this, &ValgrindToolRunner::runnerFinished); - reportSuccess(); + reportStarted(); } void ValgrindToolRunner::receiveProcessOutput(const QString &output, OutputFormat format) diff --git a/src/plugins/valgrind/valgrindengine.h b/src/plugins/valgrind/valgrindengine.h index 874fdf284ce..6a41d68000f 100644 --- a/src/plugins/valgrind/valgrindengine.h +++ b/src/plugins/valgrind/valgrindengine.h @@ -37,7 +37,7 @@ namespace Valgrind { namespace Internal { -class ValgrindToolRunner : public ProjectExplorer::ToolRunner +class ValgrindToolRunner : public ProjectExplorer::RunWorker { Q_OBJECT diff --git a/src/plugins/winrt/winrtdebugsupport.cpp b/src/plugins/winrt/winrtdebugsupport.cpp index a3f31072a16..1cb2c6b1249 100644 --- a/src/plugins/winrt/winrtdebugsupport.cpp +++ b/src/plugins/winrt/winrtdebugsupport.cpp @@ -49,7 +49,7 @@ namespace Internal { using namespace ProjectExplorer; WinRtDebugSupport::WinRtDebugSupport(RunControl *runControl, WinRtRunnerHelper *runner) - : ToolRunner(runControl) + : RunWorker(runControl) , m_runner(runner) { connect(runControl, &RunControl::finished, this, &WinRtDebugSupport::finish); diff --git a/src/plugins/winrt/winrtdebugsupport.h b/src/plugins/winrt/winrtdebugsupport.h index 630463d44c3..177e8157c18 100644 --- a/src/plugins/winrt/winrtdebugsupport.h +++ b/src/plugins/winrt/winrtdebugsupport.h @@ -35,7 +35,7 @@ namespace Internal { class WinRtRunConfiguration; class WinRtRunnerHelper; -class WinRtDebugSupport : public ProjectExplorer::ToolRunner +class WinRtDebugSupport : public ProjectExplorer::RunWorker { Q_OBJECT public: