Commit 548df938 authored by Christian Kandeler's avatar Christian Kandeler
Browse files

Maemo: Use dynamic port list.

Check whether the ports we need are actually available on the device.
As a side effect, this makes it possible to debug more than one
application at the same time on Maemo.

Task-number: QTCREATORBUG-2702
parent 8415d0fa
......@@ -710,15 +710,15 @@ Internal::AbstractGdbAdapter *DebuggerRunControl::gdbAdapter() const
return engine->gdbAdapter();
}
void DebuggerRunControl::handleRemoteSetupDone()
void DebuggerRunControl::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
{
if (QmlEngine *qmlEngine = qobject_cast<QmlEngine *>(d->m_engine)) {
qmlEngine->handleRemoteSetupDone();
qmlEngine->handleRemoteSetupDone(qmlPort);
} else if (Internal::AbstractGdbAdapter *adapter = gdbAdapter()) {
if (RemotePlainGdbAdapter *rpga = qobject_cast<RemotePlainGdbAdapter *>(adapter)) {
rpga->handleSetupDone();
rpga->handleSetupDone(qmlPort);
} else if (RemoteGdbServerAdapter *rgsa = qobject_cast<RemoteGdbServerAdapter *>(adapter)) {
rgsa->handleSetupDone();
rgsa->handleSetupDone(gdbServerPort, qmlPort);
} else {
QTC_ASSERT(false, /* */ );
}
......
......@@ -115,7 +115,7 @@ public:
void showMessage(const QString &msg, int channel);
void handleRemoteSetupDone();
void handleRemoteSetupDone(int gdbServerPort, int qmlPort);
void handleRemoteSetupFailed(const QString &message);
static bool checkDebugConfiguration(int toolChain,
......
......@@ -89,6 +89,8 @@ protected:
{ return m_engine->state(); }
const DebuggerStartParameters &startParameters() const
{ return m_engine->startParameters(); }
DebuggerStartParameters &startParameters()
{ return m_engine->startParameters(); }
void showMessage(const QString &msg, int channel = LogDebug, int timeout = 1)
{ m_engine->showMessage(msg, channel, timeout); }
......
......@@ -286,10 +286,25 @@ void RemoteGdbServerAdapter::shutdownAdapter()
m_engine->notifyAdapterShutdownOk();
}
void RemoteGdbServerAdapter::handleSetupDone()
void RemoteGdbServerAdapter::handleSetupDone(int gdbServerPort, int qmlPort)
{
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
if (qmlPort != -1)
startParameters().qmlServerPort = qmlPort;
if (gdbServerPort != -1) {
QString &rc = startParameters().remoteChannel;
const int sepIndex = rc.lastIndexOf(QLatin1Char(':'));
if (sepIndex != -1) {
rc.replace(sepIndex + 1, rc.count() - sepIndex - 1,
QString::number(gdbServerPort));
}
}
handleSetupDone();
}
void RemoteGdbServerAdapter::handleSetupDone()
{
if (m_engine->startGdb(QStringList(), startParameters().debuggerCommand))
m_engine->handleAdapterStarted();
}
......
......@@ -49,7 +49,7 @@ class RemoteGdbServerAdapter : public AbstractGdbAdapter
public:
RemoteGdbServerAdapter(GdbEngine *engine, int toolChainType, QObject *parent = 0);
void handleSetupDone();
void handleSetupDone(int gdbServerPort, int qmlPort);
void handleSetupFailed(const QString &reason);
private:
......@@ -64,6 +64,8 @@ private:
AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
void handleSetupDone();
signals:
/*
* For "external" clients of a debugger run control that need to do
......
......@@ -101,10 +101,12 @@ void RemotePlainGdbAdapter::shutdownAdapter()
m_engine->notifyAdapterShutdownOk();
}
void RemotePlainGdbAdapter::handleSetupDone()
void RemotePlainGdbAdapter::handleSetupDone(int qmlPort)
{
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
if (qmlPort != -1)
startParameters().qmlServerPort = qmlPort;
if (!startParameters().workingDirectory.isEmpty())
m_gdbProc.setWorkingDirectory(startParameters().workingDirectory);
if (!startParameters().environment.isEmpty())
......
......@@ -43,7 +43,7 @@ class RemotePlainGdbAdapter : public AbstractPlainGdbAdapter
public:
friend class RemoteGdbProcess;
explicit RemotePlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
void handleSetupDone();
void handleSetupDone(int qmlPort);
void handleSetupFailed(const QString &reason);
signals:
......
......@@ -282,8 +282,10 @@ void QmlEngine::runEngine()
showMessage(tr("QML Debugger connecting..."), StatusBar);
}
void QmlEngine::handleRemoteSetupDone()
void QmlEngine::handleRemoteSetupDone(int port)
{
if (port != -1)
startParameters().qmlServerPort = port;
notifyInferiorSetupOk();
}
......
......@@ -48,7 +48,7 @@ public:
explicit QmlEngine(const DebuggerStartParameters &startParameters);
virtual ~QmlEngine();
void handleRemoteSetupDone();
void handleRemoteSetupDone(int port);
void handleRemoteSetupFailed(const QString &message);
void setAttachToRunningExternalApp(bool value);
......
......@@ -37,8 +37,8 @@
#include "maemodeployables.h"
#include "maemodeploystep.h"
#include "maemoglobal.h"
#include "maemorunconfiguration.h"
#include "maemosshrunner.h"
#include "maemousedportsgatherer.h"
#include <coreplugin/ssh/sftpchannel.h>
#include <debugger/debuggerplugin.h>
......@@ -69,7 +69,7 @@ RunControl *MaemoDebugSupport::createDebugRunControl(MaemoRunConfiguration *runC
= runConfig->debuggingType();
if (debuggingType != MaemoRunConfiguration::DebugCppOnly) {
params.qmlServerAddress = runConfig->deviceConfig().server.host;
params.qmlServerPort = qmlServerPort(runConfig);
params.qmlServerPort = -1;
}
if (debuggingType != MaemoRunConfiguration::DebugQmlOnly) {
params.processArgs = runConfig->arguments();
......@@ -97,8 +97,7 @@ RunControl *MaemoDebugSupport::createDebugRunControl(MaemoRunConfiguration *runC
params.startMode = AttachToRemote;
params.executable = runConfig->localExecutableFilePath();
params.debuggerCommand = runConfig->gdbCmd();
params.remoteChannel = devConf.server.host + QLatin1Char(':')
+ QString::number(gdbServerPort(runConfig));
params.remoteChannel = devConf.server.host + QLatin1String(":-1");
params.useServerStartScript = true;
params.remoteArchitecture = QLatin1String("arm");
params.gnuTarget = QLatin1String("arm-none-linux-gnueabi");
......@@ -118,8 +117,8 @@ MaemoDebugSupport::MaemoDebugSupport(MaemoRunConfiguration *runConfig,
: QObject(runControl), m_runControl(runControl), m_runConfig(runConfig),
m_deviceConfig(m_runConfig->deviceConfig()),
m_runner(new MaemoSshRunner(this, m_runConfig, true)),
m_qmlOnlyDebugging(m_runConfig->debuggingType() == MaemoRunConfiguration::DebugQmlOnly),
m_state(Inactive)
m_debuggingType(m_runConfig->debuggingType()),
m_state(Inactive), m_gdbServerPort(-1), m_qmlPort(-1)
{
connect(m_runControl, SIGNAL(engineRequestSetup()), this,
SLOT(handleAdapterSetupRequested()));
......@@ -169,8 +168,18 @@ void MaemoDebugSupport::startExecution()
ASSERT_STATE(StartingRunner);
if (!useGdb() && m_debuggingType != MaemoRunConfiguration::DebugQmlOnly) {
if (!setPort(m_gdbServerPort))
return;
}
if (m_debuggingType != MaemoRunConfiguration::DebugCppOnly) {
if (!setPort(m_qmlPort))
return;
}
const QString &dumperLib = m_runConfig->dumperLib();
if (!m_qmlOnlyDebugging && !dumperLib.isEmpty()
if (m_debuggingType != MaemoRunConfiguration::DebugQmlOnly
&& !dumperLib.isEmpty()
&& m_runConfig->deployStep()->currentlyNeedsDeployment(m_deviceConfig.server.host,
MaemoDeployable(dumperLib, uploadDir(m_deviceConfig)))) {
setState(InitializingUploader);
......@@ -261,11 +270,12 @@ void MaemoDebugSupport::startDebugging()
const QString cmdPrefix = MaemoGlobal::remoteCommandPrefix(remoteExe);
const QString env = environment(m_runConfig);
const QString args = m_runConfig->arguments().join(QLatin1String(" "));
const QString remoteCommandLine = m_qmlOnlyDebugging
const QString remoteCommandLine
= m_debuggingType == MaemoRunConfiguration::DebugQmlOnly
? QString::fromLocal8Bit("%1 %2 %3 %4").arg(cmdPrefix).arg(env)
.arg(remoteExe).arg(args)
: QString::fromLocal8Bit("%1 %2 gdbserver :%3 %4 %5")
.arg(cmdPrefix).arg(env).arg(gdbServerPort(m_runConfig))
.arg(cmdPrefix).arg(env).arg(m_gdbServerPort)
.arg(remoteExe).arg(args);
m_runner->startExecution(remoteCommandLine.toUtf8());
}
......@@ -291,7 +301,8 @@ void MaemoDebugSupport::handleRemoteErrorOutput(const QByteArray &output)
return;
m_runControl->showMessage(QString::fromUtf8(output), AppOutput);
if (m_state == StartingRemoteProcess && !m_qmlOnlyDebugging) {
if (m_state == StartingRemoteProcess
&& m_debuggingType != MaemoRunConfiguration::DebugQmlOnly) {
m_gdbserverOutput += output;
if (m_gdbserverOutput.contains("Listening on port")) {
handleAdapterSetupDone();
......@@ -315,7 +326,7 @@ void MaemoDebugSupport::handleAdapterSetupFailed(const QString &error)
void MaemoDebugSupport::handleAdapterSetupDone()
{
setState(Debugging);
m_runControl->handleRemoteSetupDone();
m_runControl->handleRemoteSetupDone(m_gdbServerPort, m_qmlPort);
}
void MaemoDebugSupport::setState(State newState)
......@@ -332,19 +343,6 @@ void MaemoDebugSupport::setState(State newState)
}
}
int MaemoDebugSupport::gdbServerPort(const MaemoRunConfiguration *rc)
{
return rc->freePorts().getNext();
}
int MaemoDebugSupport::qmlServerPort(const MaemoRunConfiguration *rc)
{
MaemoPortList portList = rc->freePorts();
if (rc->debuggingType() != MaemoRunConfiguration::DebugQmlOnly)
portList.getNext();
return portList.getNext();
}
QString MaemoDebugSupport::environment(const MaemoRunConfiguration *rc)
{
QList<Utils::EnvironmentItem> env = rc->userEnvironmentChanges();
......@@ -364,7 +362,17 @@ QString MaemoDebugSupport::uploadDir(const MaemoDeviceConfig &devConf)
bool MaemoDebugSupport::useGdb() const
{
return m_runControl->engine()->startParameters().startMode == StartRemoteGdb
&& !m_qmlOnlyDebugging;
&& m_debuggingType != MaemoRunConfiguration::DebugQmlOnly;
}
bool MaemoDebugSupport::setPort(int &port)
{
port = m_runner->usedPortsGatherer()->getNextFreePort(m_runner->freePorts());
if (port == -1) {
handleAdapterSetupFailed(tr("Not enough free ports on device for debugging."));
return false;
}
return true;
}
} // namespace Internal
......
......@@ -36,6 +36,7 @@
#define MAEMODEBUGSUPPORT_H
#include "maemodeviceconfigurations.h"
#include "maemorunconfiguration.h"
#include <coreplugin/ssh/sftpdefs.h>
......@@ -87,8 +88,6 @@ private:
DumpersUploaded, StartingRemoteProcess, Debugging
};
static int gdbServerPort(const MaemoRunConfiguration *rc);
static int qmlServerPort(const MaemoRunConfiguration *rc);
static QString environment(const MaemoRunConfiguration *rc);
void handleAdapterSetupFailed(const QString &error);
......@@ -96,17 +95,20 @@ private:
void startDebugging();
bool useGdb() const;
void setState(State newState);
bool setPort(int &port);
const QPointer<Debugger::DebuggerRunControl> m_runControl;
MaemoRunConfiguration * const m_runConfig;
const MaemoDeviceConfig m_deviceConfig;
MaemoSshRunner * const m_runner;
const bool m_qmlOnlyDebugging;
const MaemoRunConfiguration::DebuggingType m_debuggingType;
QSharedPointer<Core::SftpChannel> m_uploader;
Core::SftpJobId m_uploadJob;
QByteArray m_gdbserverOutput;
State m_state;
int m_gdbServerPort;
int m_qmlPort;
};
} // namespace Internal
......
......@@ -424,7 +424,7 @@ void MaemoDeployStep::handleUnmounted()
prepareSftpConnection();
break;
case CurrentDirsUnmount:
m_mounter->mount();
// m_mounter->mount(); TODO: See above
break;
case CurrentMountsUnmount:
writeOutput(tr("Deployment finished."));
......@@ -452,7 +452,6 @@ void MaemoDeployStep::setupMount()
Q_ASSERT(m_needsInstall || !m_filesToCopy.isEmpty());
m_mounter->resetMountSpecifications();
m_mounter->setToolchain(toolChain());
m_mounter->setPortList(deviceConfig().freePorts());
if (m_needsInstall) {
const QString localDir
= QFileInfo(packagingStep()->packageFilePath()).absolutePath();
......
......@@ -31,6 +31,7 @@
#include "maemoglobal.h"
#include "maemotoolchain.h"
#include "maemousedportsgatherer.h"
#include <coreplugin/ssh/sftpchannel.h>
#include <coreplugin/ssh/sshconnection.h>
......@@ -72,13 +73,9 @@ bool MaemoRemoteMounter::addMountSpecification(const MaemoMountSpecification &mo
Q_ASSERT(m_toolChain);
ASSERT_STATE(Inactive);
if (m_toolChain->allowsRemoteMounts() && mountSpec.isValid()) {
if (!m_portList.hasMore())
return false;
else
m_mountSpecs << MountInfo(mountSpec, m_portList.getNext(), mountAsRoot);
}
return true;
if (m_toolChain->allowsRemoteMounts() && mountSpec.isValid())
m_mountSpecs << MountInfo(mountSpec, mountAsRoot);
return true; // TODO: Function can't fail anymore. Make void and remove all checks
}
bool MaemoRemoteMounter::hasValidMountSpecifications() const
......@@ -86,7 +83,8 @@ bool MaemoRemoteMounter::hasValidMountSpecifications() const
return !m_mountSpecs.isEmpty();
}
void MaemoRemoteMounter::mount()
void MaemoRemoteMounter::mount(MaemoPortList *freePorts,
const MaemoUsedPortsGatherer *portsGatherer)
{
ASSERT_STATE(Inactive);
Q_ASSERT(m_utfsServers.isEmpty());
......@@ -97,6 +95,8 @@ void MaemoRemoteMounter::mount()
emit reportProgress(tr("No directories to mount"));
emit mounted();
} else {
m_freePorts = freePorts;
m_portsGatherer = portsGatherer;
deployUtfsClient();
}
}
......@@ -259,7 +259,15 @@ void MaemoRemoteMounter::startUtfsClients()
const QLatin1String andOp(" && ");
QString remoteCall = chmodFuse + andOp + chmodUtfsClient;
for (int i = 0; i < m_mountSpecs.count(); ++i) {
const MountInfo &mountInfo = m_mountSpecs.at(i);
MountInfo &mountInfo = m_mountSpecs[i];
mountInfo.remotePort
= m_portsGatherer->getNextFreePort(m_freePorts);
if (mountInfo.remotePort == -1) {
setState(Inactive);
emit error(tr("Error: Not enough free ports on device to fulfill all mount requests."));
return;
}
const MaemoMountSpecification &mountSpec = mountInfo.mountSpec;
const QString mkdir = QString::fromLocal8Bit("%1 mkdir -p %2")
.arg(MaemoGlobal::remoteSudo(), mountSpec.remoteMountPoint);
......@@ -378,7 +386,6 @@ void MaemoRemoteMounter::handleUtfsServerError(QProcess::ProcessError)
.arg(QString::fromLocal8Bit(errorOutput));
}
killAllUtfsServers();
killUtfsClients();
emit error(tr("Error running UTFS server: %1").arg(errorString));
setState(Inactive);
......@@ -436,7 +443,6 @@ void MaemoRemoteMounter::handleUtfsServerTimeout()
return;
killAllUtfsServers();
killUtfsClients();
emit error(tr("Timeout waiting for UTFS servers to connect."));
setState(Inactive);
......@@ -449,15 +455,5 @@ void MaemoRemoteMounter::setState(State newState)
m_state = newState;
}
// TODO: Perhaps remove this one again, since it might interfere with
// an unrelated application
void MaemoRemoteMounter::killUtfsClients()
{
const SshRemoteProcess::Ptr utfsClientKiller
= m_connection->createRemoteProcess("pkill utfs-client; sleep 1; "
"pkill -9 utfs-client");
utfsClientKiller->start();
}
} // namespace Internal
} // namespace Qt4ProjectManager
......@@ -52,6 +52,7 @@ class SshRemoteProcess;
namespace Qt4ProjectManager {
namespace Internal {
class MaemoToolChain;
class MaemoUsedPortsGatherer;
class MaemoRemoteMounter : public QObject
{
......@@ -60,12 +61,12 @@ public:
MaemoRemoteMounter(QObject *parent);
~MaemoRemoteMounter();
void setToolchain(const MaemoToolChain *toolchain) { m_toolChain = toolchain; }
void setPortList(const MaemoPortList &portList) { m_portList = portList; }
bool addMountSpecification(const MaemoMountSpecification &mountSpec,
bool mountAsRoot);
bool hasValidMountSpecifications() const;
void resetMountSpecifications() { m_mountSpecs.clear(); }
void mount();
void mount(MaemoPortList *freePorts,
const MaemoUsedPortsGatherer *portsGatherer);
void unmount();
void stop();
......@@ -107,7 +108,6 @@ private:
void startUtfsClients();
void killUtfsServer(QProcess *proc);
void killAllUtfsServers();
void killUtfsClients();
QString utfsClientOnDevice() const;
QString utfsServer() const;
......@@ -115,11 +115,11 @@ private:
QTimer * const m_utfsServerTimer;
struct MountInfo {
MountInfo(const MaemoMountSpecification &m, int port, bool root)
: mountSpec(m), remotePort(port), mountAsRoot(root) {}
MountInfo(const MaemoMountSpecification &m, bool root)
: mountSpec(m), mountAsRoot(root), remotePort(-1) {}
MaemoMountSpecification mountSpec;
int remotePort;
bool mountAsRoot;
int remotePort;
};
QSharedPointer<Core::SshConnection> m_connection;
......@@ -134,7 +134,8 @@ private:
QByteArray m_utfsClientStderr;
QByteArray m_umountStderr;
MaemoPortList m_portList;
MaemoPortList *m_freePorts;
const MaemoUsedPortsGatherer *m_portsGatherer;
State m_state;
};
......
......@@ -40,6 +40,7 @@
#include "maemoremotemounter.h"
#include "maemoremotemountsmodel.h"
#include "maemorunconfiguration.h"
#include "maemousedportsgatherer.h"
#include <coreplugin/ssh/sshconnection.h>
#include <coreplugin/ssh/sshremoteprocess.h>
......@@ -59,14 +60,12 @@ MaemoSshRunner::MaemoSshRunner(QObject *parent,
MaemoRunConfiguration *runConfig, bool debugging)
: QObject(parent), m_runConfig(runConfig),
m_mounter(new MaemoRemoteMounter(this)),
m_portsGatherer(new MaemoUsedPortsGatherer(this)),
m_devConfig(runConfig->deviceConfig()),
m_freePorts(runConfig->freePorts()),
m_debugging(debugging), m_state(Inactive)
{
m_procsToKill
<< QFileInfo(m_runConfig->localExecutableFilePath()).fileName()
<< QLatin1String("utfs-client");
if (debugging)
m_procsToKill << QLatin1String("gdbserver");
m_procsToKill << QFileInfo(m_runConfig->localExecutableFilePath()).fileName();
connect(m_mounter, SIGNAL(mounted()), this, SLOT(handleMounted()));
connect(m_mounter, SIGNAL(unmounted()), this, SLOT(handleUnmounted()));
connect(m_mounter, SIGNAL(error(QString)), this,
......@@ -75,6 +74,10 @@ MaemoSshRunner::MaemoSshRunner(QObject *parent,
SIGNAL(reportProgress(QString)));
connect(m_mounter, SIGNAL(debugOutput(QString)), this,
SIGNAL(mountDebugOutput(QString)));
connect(m_portsGatherer, SIGNAL(error(QString)), this,
SLOT(handlePortsGathererError(QString)));
connect(m_portsGatherer, SIGNAL(portListReady()), this,
SLOT(handleUsedPortsAvailable()));
}
MaemoSshRunner::~MaemoSshRunner() {}
......@@ -191,36 +194,23 @@ void MaemoSshRunner::handleUnmounted()
switch (m_state) {
case PreRunCleaning: {
m_mounter->resetMountSpecifications();
MaemoPortList portList = m_devConfig.freePorts();
if (m_debugging) { // gdbserver and QML inspector need one port each.
MaemoRunConfiguration::DebuggingType debuggingType
= m_runConfig->debuggingType();
if (debuggingType != MaemoRunConfiguration::DebugQmlOnly
&& !m_runConfig->useRemoteGdb())
portList.getNext();
if (debuggingType != MaemoRunConfiguration::DebugCppOnly)
portList.getNext();
}
m_mounter->setToolchain(m_runConfig->toolchain());
m_mounter->setPortList(portList);
const MaemoRemoteMountsModel * const remoteMounts
= m_runConfig->remoteMounts();
for (int i = 0; i < remoteMounts->mountSpecificationCount(); ++i) {
if (!addMountSpecification(remoteMounts->mountSpecificationAt(i)))
return;
}
for (int i = 0; i < remoteMounts->mountSpecificationCount(); ++i)
m_mounter->addMountSpecification(remoteMounts->mountSpecificationAt(i), false);
if (m_debugging && m_runConfig->useRemoteGdb()) {
if (!addMountSpecification(MaemoMountSpecification(
m_mounter->addMountSpecification(MaemoMountSpecification(
m_runConfig->localDirToMountForRemoteGdb(),
MaemoGlobal::remoteProjectSourcesMountPoint())))
return;
MaemoGlobal::remoteProjectSourcesMountPoint()), false);
}
setState(PreMountUnmounting);
unmount();
break;
}
case PreMountUnmounting:
mount();
setState(GatheringPorts);
m_portsGatherer->start(m_connection, m_freePorts);
break;
case PostRunCleaning:
case StopRequested: {
......@@ -295,16 +285,6 @@ void MaemoSshRunner::handleRemoteProcessFinished(int exitStatus)
}
}
bool MaemoSshRunner::addMountSpecification(const MaemoMountSpecification &mountSpec)
{
if (!m_mounter->addMountSpecification(mountSpec, false)) {
emitError(tr("The device does not have enough free ports "
"for this run configuration."));
return false;
}
return true;
}
bool MaemoSshRunner::isConnectionUsable() const
{
return m_connection && m_connection->state() == SshConnection::Connected
......@@ -315,6 +295,7 @@ void MaemoSshRunner::setState(State newState)
{
if (newState == Inactive) {
m_mounter->setConnection(SshConnection::Ptr());
m_portsGatherer->stop();
if (m_connection) {
disconnect(m_connection.data(), 0, this, 0);
m_connection = SshConnection::Ptr();
......@@ -338,7 +319,7 @@ void MaemoSshRunner::mount()
setState(Mounting);
if (m_mounter->hasValidMountSpecifications()) {
emit reportProgress(tr("Mounting host directories..."));
m_mounter->mount();
m_mounter->mount(freePorts(), m_portsGatherer);
} else {
handleMounted();
}
......@@ -369,6 +350,21 @@ void MaemoSshRunner::unmount()
}
}
void MaemoSshRunner::handlePortsGathererError(const QString &errorMsg)
{
emitError(errorMsg);
}
void MaemoSshRunner::handleUsedPortsAvailable()
{
ASSERT_STATE(QList<State>() << GatheringPorts << StopRequested);
if (m_state == StopRequested) {