ProjectExplorer: Introduce DeviceProcessSignalOperation.

Every device can now return a DeviceProcessSignalOperation,
which allows to kill or interrupt processes running on the
device.

Change-Id: Idaa04ebc767e09ca167fa033ed93860b9b81479e
Reviewed-by: Christian Kandeler <christian.kandeler@digia.com>
Reviewed-by: David Kaspar <dkaspar@blackberry.com>
Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
David Schulz
2013-09-16 15:30:30 +02:00
parent ca15d0aa95
commit a06af35631
32 changed files with 703 additions and 216 deletions

View File

@@ -89,6 +89,11 @@ bool AndroidDevice::canAutoDetectPorts() const
return true;
}
DeviceProcessSignalOperation::Ptr AndroidDevice::signalOperation() const
{
return DeviceProcessSignalOperation::Ptr();
}
IDevice::Ptr AndroidDevice::clone() const
{
return IDevice::Ptr(new AndroidDevice(*this));

View File

@@ -47,6 +47,7 @@ public:
QString displayNameForActionId(Core::Id actionId) const;
void executeAction(Core::Id actionId, QWidget *parent = 0);
bool canAutoDetectPorts() const;
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const;
ProjectExplorer::IDevice::Ptr clone() const;

View File

@@ -32,6 +32,7 @@
#include "deviceprocesslist.h"
#include "localprocesslist.h"
#include "desktopdeviceconfigurationwidget.h"
#include "desktopprocesssignaloperation.h"
#include <projectexplorer/projectexplorerconstants.h>
#include <ssh/sshconnection.h>
@@ -114,6 +115,11 @@ DeviceProcess *DesktopDevice::createProcess(QObject *parent) const
return new Internal::DesktopDeviceProcess(sharedFromThis(), parent);
}
DeviceProcessSignalOperation::Ptr DesktopDevice::signalOperation() const
{
return DeviceProcessSignalOperation::Ptr(new DesktopProcessSignalOperation());
}
IDevice::Ptr DesktopDevice::clone() const
{
return Ptr(new DesktopDevice(*this));

View File

@@ -55,6 +55,7 @@ public:
DeviceProcessList *createProcessListModel(QObject *parent) const;
bool canCreateProcess() const { return true; }
DeviceProcess *createProcess(QObject *parent) const;
DeviceProcessSignalOperation::Ptr signalOperation() const;
IDevice::Ptr clone() const;

View File

@@ -28,13 +28,11 @@
****************************************************************************/
#include "desktopdeviceprocess.h"
#include "idevice.h"
#include <utils/environment.h>
#include <utils/qtcassert.h>
#ifdef Q_OS_UNIX
#include <signal.h>
#endif
#include <utils/qtcprocess.h>
namespace ProjectExplorer {
namespace Internal {
@@ -59,11 +57,7 @@ void DesktopDeviceProcess::start(const QString &executable, const QStringList &a
void DesktopDeviceProcess::interrupt()
{
#ifdef Q_OS_UNIX
::kill(m_process->pid(), SIGINT);
#elif defined(Q_OS_WIN)
// tbd
#endif
device()->signalOperation()->interruptProcess(Utils::qPidToPid(m_process->pid()));
}
void DesktopDeviceProcess::terminate()

View File

@@ -0,0 +1,221 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "desktopprocesssignaloperation.h"
#include "localprocesslist.h"
#include <utils/winutils.h>
#include <QDir>
#ifdef Q_OS_WIN
#define _WIN32_WINNT 0x0502
#include <windows.h>
#ifndef PROCESS_SUSPEND_RESUME
#define PROCESS_SUSPEND_RESUME 0x0800
#endif // PROCESS_SUSPEND_RESUME
#else // Q_OS_WIN
#include <errno.h>
#include <signal.h>
#endif // else Q_OS_WIN
namespace ProjectExplorer {
void DesktopProcessSignalOperation::killProcess(int pid)
{
killProcessSilently(pid);
emit finished(m_errorMessage);
}
void DesktopProcessSignalOperation::killProcess(const QString &filePath)
{
m_errorMessage.clear();
foreach (const DeviceProcessItem &process, Internal::LocalProcessList::getLocalProcesses()) {
if (process.cmdLine == filePath)
killProcessSilently(process.pid);
}
emit finished(m_errorMessage);
}
void DesktopProcessSignalOperation::interruptProcess(int pid)
{
m_errorMessage.clear();
interruptProcessSilently(pid);
emit finished(m_errorMessage);
}
void DesktopProcessSignalOperation::interruptProcess(const QString &filePath)
{
interruptProcess(filePath, NoSpecialInterrupt);
}
void DesktopProcessSignalOperation::interruptProcess(int pid, SpecialInterrupt specialInterrupt)
{
m_errorMessage.clear();
interruptProcessSilently(pid, specialInterrupt);
}
void DesktopProcessSignalOperation::interruptProcess(const QString &filePath,
SpecialInterrupt specialInterrupt)
{
m_errorMessage.clear();
foreach (const DeviceProcessItem &process, Internal::LocalProcessList::getLocalProcesses()) {
if (process.cmdLine == filePath)
interruptProcessSilently(process.pid, specialInterrupt);
}
emit finished(m_errorMessage);
}
void DesktopProcessSignalOperation::appendMsgCannotKill(int pid, const QString &why)
{
if (!m_errorMessage.isEmpty())
m_errorMessage += QChar::fromLatin1('\n');
m_errorMessage += tr("Cannot kill process with pid %1: %3 ").arg(pid).arg(why);
}
void DesktopProcessSignalOperation::appendMsgCannotInterrupt(int pid, const QString &why)
{
if (!m_errorMessage.isEmpty())
m_errorMessage += QChar::fromLatin1('\n');
m_errorMessage += tr("Cannot interrupt process with pid %1: %3 ").arg(pid).arg(why);
}
void DesktopProcessSignalOperation::killProcessSilently(int pid)
{
#ifdef Q_OS_WIN
const DWORD rights = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION
|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ
|PROCESS_DUP_HANDLE|PROCESS_TERMINATE|PROCESS_CREATE_THREAD|PROCESS_SUSPEND_RESUME;
if (const HANDLE handle = OpenProcess(rights, FALSE, pid)) {
if (!TerminateProcess(handle, UINT(-1)))
appendMsgCannotKill(pid, Utils::winErrorMessage(GetLastError()));
CloseHandle(handle);
} else {
appendMsgCannotKill(pid, tr("Cannot open process."));
}
#else
if (pid <= 0)
appendMsgCannotKill(pid, tr("Invalid process id."));
else if (kill(pid, SIGKILL))
appendMsgCannotKill(pid, QString::fromLocal8Bit(strerror(errno)));
#endif // Q_OS_WIN
}
void DesktopProcessSignalOperation::interruptProcessSilently(
int pid, SpecialInterrupt specialInterrupt)
{
#ifdef Q_OS_WIN
/*
Windows 64 bit has a 32 bit subsystem (WOW64) which makes it possible to run a
32 bit application inside a 64 bit environment.
When GDB is used DebugBreakProcess must be called from the same system (32/64 bit) running
the inferior. If CDB is used we could in theory break wow64 processes,
but the break is actually a wow64 breakpoint. CDB is configured to ignore these
breakpoints, because they also appear on module loading.
Therefore we need helper executables (win(32/64)interrupt.exe) on Windows 64 bit calling
DebugBreakProcess from the correct system.
DebugBreak matrix for windows
Api = UseDebugBreakApi
Win64 = UseWin64InterruptHelper
Win32 = UseWin32InterruptHelper
N/A = This configuration is not possible
| Windows 32bit | Windows 64bit
| QtCreator 32bit | QtCreator 32bit | QtCreator 64bit
| Inferior 32bit | Inferior 32bit | Inferior 64bit | Inferior 32bit | Inferior 64bit
----------|-----------------|-----------------|-----------------|-----------------|----------------
CDB 32bit | Api | Api | N/A | Win32 | N/A
64bit | N/A | Win64 | Win64 | Api | Api
----------|-----------------|-----------------|-----------------|-----------------|----------------
GDB 32bit | Api | Api | N/A | Win32 | N/A
64bit | N/A | N/A | Win64 | N/A | Api
----------|-----------------|-----------------|-----------------|-----------------|----------------
*/
HANDLE inferior = NULL;
do {
const DWORD rights = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION
|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ
|PROCESS_DUP_HANDLE|PROCESS_TERMINATE|PROCESS_CREATE_THREAD|PROCESS_SUSPEND_RESUME;
inferior = OpenProcess(rights, FALSE, pid);
if (inferior == NULL) {
appendMsgCannotInterrupt(pid, tr("Cannot open process: %1")
+ Utils::winErrorMessage(GetLastError()));
break;
}
bool creatorIs64Bit = Utils::winIs64BitBinary(qApp->applicationFilePath());
if (!Utils::winIs64BitSystem() ||
specialInterrupt == NoSpecialInterrupt ||
specialInterrupt == Win64Interrupt && creatorIs64Bit ||
specialInterrupt == Win32Interrupt && !creatorIs64Bit) {
if (!DebugBreakProcess(inferior)) {
appendMsgCannotInterrupt(pid, tr("DebugBreakProcess failed: ")
+ Utils::winErrorMessage(GetLastError()));
}
} else if (specialInterrupt == Win32Interrupt
|| specialInterrupt == Win64Interrupt) {
QString executable = QCoreApplication::applicationDirPath();
executable += specialInterrupt == Win32Interrupt
? QLatin1String("/win32interrupt.exe")
: QLatin1String("/win64interrupt.exe");
if (!QFile::exists(executable)) {
appendMsgCannotInterrupt(pid, tr( "%1 does not exist. If you have built QtCreator "
"on your own ,checkout http://qt.gitorious.org/"
"qt-creator/binary-artifacts.").
arg(QDir::toNativeSeparators(executable)));
}
switch (QProcess::execute(executable, QStringList(QString::number(pid)))) {
case -2:
appendMsgCannotInterrupt(pid, tr(
"Cannot start %1. Check src\\tools\\win64interrupt\\win64interrupt.c "
"for more information.").arg(QDir::toNativeSeparators(executable)));
break;
case 0:
break;
default:
appendMsgCannotInterrupt(pid, QDir::toNativeSeparators(executable)
+ tr(" could not break the process."));
break;
}
}
} while (false);
if (inferior != NULL)
CloseHandle(inferior);
#else
Q_UNUSED(specialInterrupt)
if (pid <= 0)
appendMsgCannotInterrupt(pid, tr("Invalid process id."));
else if (kill(pid, SIGINT))
appendMsgCannotInterrupt(pid, QString::fromLocal8Bit(strerror(errno)));
#endif // Q_OS_WIN
}
} // namespace ProjectExplorer

View File

@@ -1,9 +1,7 @@
/**************************************************************************
/****************************************************************************
**
** Copyright (C) 2011 - 2013 Research In Motion
**
** Contact: Research In Motion (blackberry-qt@qnx.com)
** Contact: KDAB (info@kdab.com)
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
@@ -28,29 +26,41 @@
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef WINDOWSPROCESSSIGNALOPERATION_H
#define WINDOWSPROCESSSIGNALOPERATION_H
#include "blackberrydeviceprocesssupport.h"
#include "idevice.h"
using namespace Qnx;
using namespace Qnx::Internal;
#include <projectexplorer/projectexplorer_export.h>
static QString signalProcessByNameCommandLine(const QString &filePath, int signal)
namespace ProjectExplorer {
class PROJECTEXPLORER_EXPORT DesktopProcessSignalOperation : public DeviceProcessSignalOperation
{
QString executable = filePath;
Q_OBJECT
public:
enum SpecialInterrupt { NoSpecialInterrupt, Win32Interrupt, Win64Interrupt };
return QString::fromLatin1("for PID in $(pidin -F \"%a %A\" | grep \"%1\" | awk '/%1/ {print $1}'); "
"do "
"kill -%2 $PID; "
"done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(signal);
}
~DesktopProcessSignalOperation() {}
void killProcess(int pid);
void killProcess(const QString &filePath);
void interruptProcess(int pid);
void interruptProcess(const QString &filePath);
void interruptProcess(int pid, SpecialInterrupt specialInterrupt);
void interruptProcess(const QString &filePath, SpecialInterrupt specialInterrupt);
QString BlackBerryDeviceProcessSupport::killProcessByNameCommandLine(const QString &filePath) const
{
return QString::fromLatin1("%1; %2").arg(signalProcessByNameCommandLine(filePath, 15),
signalProcessByNameCommandLine(filePath, 9));
}
private:
void killProcessSilently(int pid);
void interruptProcessSilently(int pid, SpecialInterrupt = NoSpecialInterrupt);
QString BlackBerryDeviceProcessSupport::interruptProcessByNameCommandLine(const QString &filePath) const
{
return signalProcessByNameCommandLine(filePath, 2);
}
void appendMsgCannotKill(int pid, const QString &why);
void appendMsgCannotInterrupt(int pid, const QString &why);
protected:
explicit DesktopProcessSignalOperation() {}
friend class DesktopDevice;
};
} // namespace ProjectExplorer
#endif // WINDOWSPROCESSSIGNALOPERATION_H

View File

@@ -435,6 +435,10 @@ private:
QString displayNameForActionId(Core::Id) const { return QString(); }
void executeAction(Core::Id, QWidget *) { }
Ptr clone() const { return Ptr(new TestDevice(*this)); }
DeviceProcessSignalOperation::Ptr signalOperation() const
{
return DeviceProcessSignalOperation::Ptr();
}
};
void ProjectExplorerPlugin::testDeviceManager()

View File

@@ -196,7 +196,6 @@ public:
} // namespace Internal
PortsGatheringMethod::~PortsGatheringMethod() { }
DeviceProcessSupport::~DeviceProcessSupport() { }
DeviceTester::DeviceTester(QObject *parent) : QObject(parent) { }
IDevice::IDevice() : d(new Internal::IDevicePrivate)
@@ -255,11 +254,6 @@ Core::Id IDevice::id() const
return d->id;
}
DeviceProcessSupport::Ptr IDevice::processSupport() const
{
return DeviceProcessSupport::Ptr();
}
PortsGatheringMethod::Ptr IDevice::portsGatheringMethod() const
{
return PortsGatheringMethod::Ptr();

View File

@@ -55,15 +55,25 @@ namespace Internal { class IDevicePrivate; }
class IDeviceWidget;
class DeviceTester;
class PROJECTEXPLORER_EXPORT DeviceProcessSupport
class PROJECTEXPLORER_EXPORT DeviceProcessSignalOperation : public QObject
{
Q_OBJECT
public:
typedef QSharedPointer<const DeviceProcessSupport> Ptr;
~DeviceProcessSignalOperation() {}
typedef QSharedPointer<DeviceProcessSignalOperation> Ptr;
virtual ~DeviceProcessSupport();
virtual QString killProcessByPidCommandLine(int pid) const = 0;
virtual QString killProcessByNameCommandLine(const QString &filePath) const = 0;
virtual QString interruptProcessByNameCommandLine(const QString &filePath) const = 0;
virtual void killProcess(int pid) = 0;
virtual void killProcess(const QString &filePath) = 0;
virtual void interruptProcess(int pid) = 0;
virtual void interruptProcess(const QString &filePath) = 0;
signals:
// If the error message is empty the operation was successful
void finished(const QString &errorMessage);
protected:
explicit DeviceProcessSignalOperation() {}
QString m_errorMessage;
};
class PROJECTEXPLORER_EXPORT PortsGatheringMethod
@@ -113,7 +123,6 @@ public:
virtual QString displayNameForActionId(Core::Id actionId) const = 0;
virtual void executeAction(Core::Id actionId, QWidget *parent = 0) = 0;
virtual DeviceProcessSupport::Ptr processSupport() const;
// Devices that can auto detect ports need not return a ports gathering method. Such devices can
// obtain a free port on demand. eg: Desktop device.
virtual bool canAutoDetectPorts() const { return false; }
@@ -125,6 +134,7 @@ public:
virtual bool canCreateProcess() const { return false; }
virtual DeviceProcess *createProcess(QObject *parent) const;
virtual DeviceProcessSignalOperation::Ptr signalOperation() const = 0;
enum DeviceState { DeviceReadyToUse, DeviceConnected, DeviceDisconnected, DeviceStateUnknown };
DeviceState deviceState() const;

View File

@@ -51,9 +51,6 @@
#include <utils/winutils.h>
#include <tlhelp32.h>
#include <psapi.h>
#ifndef PROCESS_SUSPEND_RESUME
#define PROCESS_SUSPEND_RESUME 0x0800
#endif
#endif
namespace ProjectExplorer {
@@ -125,28 +122,8 @@ QList<DeviceProcessItem> LocalProcessList::getLocalProcesses()
return processes;
}
void LocalProcessList::doKillProcess(const DeviceProcessItem &process)
{
const DWORD rights = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION
|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ
|PROCESS_DUP_HANDLE|PROCESS_TERMINATE|PROCESS_CREATE_THREAD|PROCESS_SUSPEND_RESUME;
m_error.clear();
if (const HANDLE handle = OpenProcess(rights, FALSE, process.pid)) {
if (!TerminateProcess(handle, UINT(-1))) {
m_error = tr("Cannot terminate process %1: %2").
arg(process.pid).arg(Utils::winErrorMessage(GetLastError()));
}
CloseHandle(handle);
} else {
m_error = tr("Cannot open process %1: %2").
arg(process.pid).arg(Utils::winErrorMessage(GetLastError()));
}
QTimer::singleShot(0, this, SLOT(reportDelayedKillStatus()));
}
#endif //Q_OS_WIN
#ifdef Q_OS_UNIX
LocalProcessList::LocalProcessList(const IDevice::ConstPtr &device, QObject *parent)
: DeviceProcessList(device, parent)
@@ -258,17 +235,16 @@ QList<DeviceProcessItem> LocalProcessList::getLocalProcesses()
return procDir.exists() ? getLocalProcessesUsingProc(procDir) : getLocalProcessesUsingPs();
}
#endif // QT_OS_UNIX
void LocalProcessList::doKillProcess(const DeviceProcessItem &process)
{
if (kill(process.pid, SIGKILL) == -1)
m_error = QString::fromLocal8Bit(strerror(errno));
else
m_error.clear();
QTimer::singleShot(0, this, SLOT(reportDelayedKillStatus()));
DeviceProcessSignalOperation::Ptr signalOperation = device()->signalOperation();
connect(signalOperation.data(), SIGNAL(finished(QString)),
SLOT(reportDelayedKillStatus(QString)));
signalOperation->killProcess(process.pid);
}
#endif // QT_OS_UNIX
Qt::ItemFlags LocalProcessList::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = DeviceProcessList::flags(index);
@@ -287,12 +263,12 @@ void LocalProcessList::doUpdate()
QTimer::singleShot(0, this, SLOT(handleUpdate()));
}
void LocalProcessList::reportDelayedKillStatus()
void LocalProcessList::reportDelayedKillStatus(const QString &errorMessage)
{
if (m_error.isEmpty())
if (errorMessage.isEmpty())
reportProcessKilled();
else
reportError(m_error);
reportError(errorMessage);
}
} // namespace Internal

View File

@@ -57,11 +57,11 @@ private:
private slots:
void handleUpdate();
void reportDelayedKillStatus();
void reportDelayedKillStatus(const QString &errorMessage);
private:
const qint64 m_myPid;
QString m_error;
};
} // namespace Internal

View File

@@ -295,13 +295,11 @@ void SshDeviceProcess::SshDeviceProcessPrivate::doSignal(QSsh::SshRemoteProcess:
if (serverSupportsSignals) {
process->sendSignal(signal);
} else {
const DeviceProcessSupport::Ptr processSupport = q->device()->processSupport();
QString signalCommandLine = signal == QSsh::SshRemoteProcess::IntSignal
? processSupport->interruptProcessByNameCommandLine(executable)
: processSupport->killProcessByNameCommandLine(executable);
const QSsh::SshRemoteProcess::Ptr signalProcess
= connection->createRemoteProcess(signalCommandLine.toUtf8());
signalProcess->start();
DeviceProcessSignalOperation::Ptr signalOperation = q->device()->signalOperation();
if (signal == QSsh::SshRemoteProcess::IntSignal)
signalOperation->interruptProcess(executable);
else
signalOperation->killProcess(executable);
}
break;
}

View File

@@ -28,6 +28,8 @@
****************************************************************************/
#include "sshdeviceprocesslist.h"
#include "idevice.h"
#include <ssh/sshremoteprocessrunner.h>
#include <utils/qtcassert.h>
@@ -39,6 +41,7 @@ class SshDeviceProcessList::SshDeviceProcessListPrivate
{
public:
SshRemoteProcessRunner process;
DeviceProcessSignalOperation::Ptr signalOperation;
};
SshDeviceProcessList::SshDeviceProcessList(const IDevice::ConstPtr &device, QObject *parent) :
@@ -53,7 +56,6 @@ SshDeviceProcessList::~SshDeviceProcessList()
void SshDeviceProcessList::doUpdate()
{
QTC_ASSERT(device()->processSupport(), return);
connect(&d->process, SIGNAL(connectionError()), SLOT(handleConnectionError()));
connect(&d->process, SIGNAL(processClosed(int)), SLOT(handleListProcessFinished(int)));
d->process.run(listProcessesCommandLine().toUtf8(), device()->sshParameters());
@@ -61,11 +63,11 @@ void SshDeviceProcessList::doUpdate()
void SshDeviceProcessList::doKillProcess(const DeviceProcessItem &process)
{
QTC_ASSERT(device()->processSupport(), return);
connect(&d->process, SIGNAL(connectionError()), SLOT(handleConnectionError()));
connect(&d->process, SIGNAL(processClosed(int)), SLOT(handleKillProcessFinished(int)));
d->process.run(device()->processSupport()->killProcessByPidCommandLine(process.pid).toUtf8(),
device()->sshParameters());
d->signalOperation = device()->signalOperation();
QTC_ASSERT(d->signalOperation, return);
connect(d->signalOperation.data(), SIGNAL(finished(QString)),
SLOT(handleKillProcessFinished(QString)));
d->signalOperation->killProcess(process.pid);
}
void SshDeviceProcessList::handleConnectionError()
@@ -102,29 +104,13 @@ void SshDeviceProcessList::handleListProcessFinished(int exitStatus)
}
}
void SshDeviceProcessList::handleKillProcessFinished(int exitStatus)
void SshDeviceProcessList::handleKillProcessFinished(const QString &errorString)
{
setFinished();
switch (exitStatus) {
case SshRemoteProcess::FailedToStart:
handleProcessError(tr("Error: Kill process failed to start: %1")
.arg(d->process.processErrorString()));
break;
case SshRemoteProcess::CrashExit:
handleProcessError(tr("Error: Kill process crashed: %1")
.arg(d->process.processErrorString()));
break;
case SshRemoteProcess::NormalExit: {
const int exitCode = d->process.processExitCode();
if (exitCode == 0)
if (errorString.isEmpty())
reportProcessKilled();
else
handleProcessError(tr("Kill process failed with exit code %1.").arg(exitCode));
break;
}
default:
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid exit status");
}
reportError(tr("Error: Kill process failed: %1").arg(errorString));
setFinished();
}
void SshDeviceProcessList::handleProcessError(const QString &errorMessage)
@@ -139,6 +125,10 @@ void SshDeviceProcessList::handleProcessError(const QString &errorMessage)
void SshDeviceProcessList::setFinished()
{
d->process.disconnect(this);
if (d->signalOperation) {
d->signalOperation->disconnect(this);
d->signalOperation.clear();
}
}
} // namespace ProjectExplorer

View File

@@ -43,7 +43,7 @@ public:
private slots:
void handleConnectionError();
void handleListProcessFinished(int exitStatus);
void handleKillProcessFinished(int exitStatus);
void handleKillProcessFinished(const QString &errorString);
private:
virtual QString listProcessesCommandLine() const = 0;

View File

@@ -131,6 +131,7 @@ HEADERS += projectexplorer.h \
devicesupport/sshdeviceprocess.h \
devicesupport/sshdeviceprocesslist.h \
devicesupport/desktopdeviceconfigurationwidget.h \
devicesupport/desktopprocesssignaloperation.h \
deploymentdata.h \
buildtargetinfo.h \
customtoolchain.h \
@@ -254,6 +255,7 @@ SOURCES += projectexplorer.cpp \
devicesupport/sshdeviceprocess.cpp \
devicesupport/sshdeviceprocesslist.cpp \
devicesupport/desktopdeviceconfigurationwidget.cpp \
devicesupport/desktopprocesssignaloperation.cpp \
deployablefile.cpp \
customtoolchain.cpp \
projectmacroexpander.cpp \

View File

@@ -186,6 +186,7 @@ QtcPlugin {
"localprocesslist.cpp", "localprocesslist.h",
"sshdeviceprocess.cpp", "sshdeviceprocess.h",
"sshdeviceprocesslist.cpp", "sshdeviceprocesslist.h",
"desktopprocesssignaloperation.cpp", "desktopprocesssignaloperation.h",
"desktopdeviceconfigurationwidget.cpp", "desktopdeviceconfigurationwidget.h", "desktopdeviceconfigurationwidget.ui"
]
}

View File

@@ -32,11 +32,12 @@
#include "blackberrydeviceconfiguration.h"
#include "qnxconstants.h"
#include "qnxdeviceprocesssignaloperation.h"
#include "blackberrydeviceconfigurationwidget.h"
#include "blackberrydeviceconnectionmanager.h"
#include "blackberrydeviceprocesssupport.h"
#include <projectexplorer/kitinformation.h>
#include <ssh/sshconnection.h>
using namespace Qnx;
using namespace Qnx::Internal;
@@ -111,11 +112,6 @@ BlackBerryDeviceConfiguration::ConstPtr BlackBerryDeviceConfiguration::device(co
return dev.dynamicCast<const BlackBerryDeviceConfiguration>();
}
DeviceProcessSupport::Ptr BlackBerryDeviceConfiguration::processSupport() const
{
return ProjectExplorer::DeviceProcessSupport::Ptr(new BlackBerryDeviceProcessSupport);
}
QString BlackBerryDeviceConfiguration::displayType() const
{
return tr("BlackBerry");
@@ -165,3 +161,9 @@ QVariantMap BlackBerryDeviceConfiguration::toMap() const
map.insert(QLatin1String(Constants::QNX_DEBUG_TOKEN_KEY), m_debugToken);
return map;
}
DeviceProcessSignalOperation::Ptr BlackBerryDeviceConfiguration::signalOperation() const
{
return DeviceProcessSignalOperation::Ptr(
new BlackBerryDeviceProcessSignalOperation(sshParameters()));
}

View File

@@ -65,11 +65,10 @@ public:
void executeAction(Core::Id actionId, QWidget *parent);
ProjectExplorer::IDevice::Ptr clone() const;
bool hasDeviceTester() const;
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const;
static ConstPtr device(const ProjectExplorer::Kit *k);
ProjectExplorer::DeviceProcessSupport::Ptr processSupport() const;
protected:
BlackBerryDeviceConfiguration();
BlackBerryDeviceConfiguration(const QString &name, Core::Id type, MachineType machineType,

View File

@@ -163,11 +163,10 @@ void BlackBerryLogProcessRunner::killProcessRunner(QSsh::SshRemoteProcessRunner
{
QTC_ASSERT(!command.isEmpty(), return);
QString killCommand = m_device->processSupport()->killProcessByNameCommandLine(command);
QSsh::SshRemoteProcessRunner *slayProcess = new QSsh::SshRemoteProcessRunner(this);
connect(slayProcess, SIGNAL(processClosed(int)), this, SIGNAL(finished()));
slayProcess->run(killCommand.toLatin1(), m_sshParams);
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation =
m_device->signalOperation();
connect(signalOperation.data(), SIGNAL(finished(QString)), SIGNAL(finished()));
signalOperation->killProcess(command);
processRunner->cancel();

View File

@@ -72,7 +72,6 @@ SOURCES += qnxplugin.cpp \
blackberrydebugtokenuploader.cpp \
blackberrydebugtokenreader.cpp \
blackberryndkprocess.cpp \
blackberrydeviceprocesssupport.cpp \
blackberrycheckdevmodestepfactory.cpp \
blackberrycheckdevmodestep.cpp \
blackberrycheckdevmodestepconfigwidget.cpp \
@@ -96,7 +95,8 @@ SOURCES += qnxplugin.cpp \
qnxdevicetester.cpp \
blackberryconfigurationmanager.cpp \
blackberrydevicelistdetector.cpp \
blackberrylogprocessrunner.cpp
blackberrylogprocessrunner.cpp \
qnxdeviceprocesssignaloperation.cpp
HEADERS += qnxplugin.h\
qnxconstants.h \
@@ -168,7 +168,6 @@ HEADERS += qnxplugin.h\
blackberrydebugtokenuploader.h \
blackberrydebugtokenreader.h \
blackberryndkprocess.h \
blackberrydeviceprocesssupport.h \
blackberrycheckdevmodestepfactory.h \
blackberrycheckdevmodestep.h \
blackberrycheckdevmodestepconfigwidget.h \
@@ -192,7 +191,8 @@ HEADERS += qnxplugin.h\
qnxdevicetester.h \
blackberryconfigurationmanager.h \
blackberrydevicelistdetector.h \
blackberrylogprocessrunner.h
blackberrylogprocessrunner.h \
qnxdeviceprocesssignaloperation.h
FORMS += \
blackberrydeviceconfigurationwizardsetuppage.ui \

View File

@@ -115,8 +115,6 @@ QtcPlugin {
"blackberrydeviceconnectionmanager.h",
"blackberrydevicelistdetector.cpp",
"blackberrydevicelistdetector.h",
"blackberrydeviceprocesssupport.h",
"blackberrydeviceprocesssupport.cpp",
"blackberrylogprocessrunner.cpp",
"blackberrylogprocessrunner.h",
"blackberryqtversion.cpp",
@@ -215,6 +213,8 @@ QtcPlugin {
"qnxdeviceconfigurationwizard.h",
"qnxdeviceconfigurationwizardpages.cpp",
"qnxdeviceconfigurationwizardpages.h",
"qnxdeviceprocesssignaloperation.cpp",
"qnxdeviceprocesssignaloperation.h",
"qnxdevicetester.cpp",
"qnxdevicetester.h",
"qnxplugin.cpp",

View File

@@ -31,8 +31,10 @@
#include "qnxdeviceconfiguration.h"
#include "qnxdevicetester.h"
#include "qnxdeviceprocesssignaloperation.h"
#include <projectexplorer/devicesupport/sshdeviceprocesslist.h>
#include <ssh/sshconnection.h>
#include <QRegExp>
#include <QStringList>
@@ -40,30 +42,6 @@
using namespace Qnx;
using namespace Qnx::Internal;
class QnxDeviceProcessSupport : public RemoteLinux::LinuxDeviceProcessSupport
{
static QString signalProcessByNameCommandLine(const QString &filePath, int sig)
{
QString executable = filePath;
return QString::fromLatin1("for PID in $(ps -f -o pid,comm | grep %1 | awk '/%1/ {print $1}'); "
"do "
"kill -%2 $PID; "
"done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(sig);
}
QString killProcessByNameCommandLine(const QString &filePath) const
{
return QString::fromLatin1("%1; %2").arg(signalProcessByNameCommandLine(filePath, 15),
signalProcessByNameCommandLine(filePath, 9));
}
QString interruptProcessByNameCommandLine(const QString &filePath) const
{
return signalProcessByNameCommandLine(filePath, 2);
}
};
class QnxPortsGatheringMethod : public ProjectExplorer::PortsGatheringMethod
{
// TODO: The command is probably needlessly complicated because the parsing method
@@ -183,11 +161,6 @@ ProjectExplorer::IDevice::Ptr QnxDeviceConfiguration::clone() const
return Ptr(new QnxDeviceConfiguration(*this));
}
ProjectExplorer::DeviceProcessSupport::Ptr QnxDeviceConfiguration::processSupport() const
{
return ProjectExplorer::DeviceProcessSupport::Ptr(new QnxDeviceProcessSupport);
}
ProjectExplorer::PortsGatheringMethod::Ptr QnxDeviceConfiguration::portsGatheringMethod() const
{
return ProjectExplorer::PortsGatheringMethod::Ptr(new QnxPortsGatheringMethod);
@@ -202,3 +175,9 @@ ProjectExplorer::DeviceTester *QnxDeviceConfiguration::createDeviceTester() cons
{
return new QnxDeviceTester;
}
ProjectExplorer::DeviceProcessSignalOperation::Ptr QnxDeviceConfiguration::signalOperation() const
{
return ProjectExplorer::DeviceProcessSignalOperation::Ptr(
new QnxDeviceProcessSignalOperation(sshParameters()));
}

View File

@@ -50,9 +50,9 @@ public:
Origin origin = ManuallyAdded, Core::Id id = Core::Id());
ProjectExplorer::IDevice::Ptr clone() const;
ProjectExplorer::DeviceProcessSupport::Ptr processSupport() const;
ProjectExplorer::PortsGatheringMethod::Ptr portsGatheringMethod() const;
ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const;
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const;
ProjectExplorer::DeviceTester *createDeviceTester() const;
@@ -63,6 +63,10 @@ protected:
QnxDeviceConfiguration(const QString &name, Core::Id type, MachineType machineType,
Origin origin, Core::Id id);
QnxDeviceConfiguration(const QnxDeviceConfiguration &other);
QString interruptProcessByNameCommandLine(const QString &filePath) const;
QString killProcessByNameCommandLine(const QString &filePath) const;
};
} // namespace Internal

View File

@@ -0,0 +1,90 @@
/**************************************************************************
**
** Copyright (C) 2011 - 2013 Research In Motion
**
** Contact: Research In Motion (blackberry-qt@qnx.com)
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "qnxdeviceprocesssignaloperation.h"
using namespace Qnx;
using namespace Qnx::Internal;
QnxDeviceProcessSignalOperation::QnxDeviceProcessSignalOperation(
const QSsh::SshConnectionParameters sshParameters)
: RemoteLinux::RemoteLinuxSignalOperation(sshParameters)
{
}
static QString signalProcessByNameBlackBerryCommandLine(const QString &filePath, int sig)
{
QString executable = filePath;
return QString::fromLatin1("for PID in $(pidin -F \"%a %A\" | grep \"%1\" | awk '/%1/ {print $1}'); "
"do "
"kill -%2 $PID; "
"done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(sig);
}
QString QnxDeviceProcessSignalOperation::killProcessByNameCommandLine(
const QString &filePath) const
{
return QString::fromLatin1("%1; %2").arg(signalProcessByNameBlackBerryCommandLine(filePath, 15),
signalProcessByNameBlackBerryCommandLine(filePath, 9));
}
QString QnxDeviceProcessSignalOperation::interruptProcessByNameCommandLine(
const QString &filePath) const
{
return signalProcessByNameBlackBerryCommandLine(filePath, 2);
}
BlackBerryDeviceProcessSignalOperation::BlackBerryDeviceProcessSignalOperation(
const QSsh::SshConnectionParameters sshParameters)
: RemoteLinux::RemoteLinuxSignalOperation(sshParameters)
{
}
static QString signalProcessByNameQnxCommandLine(const QString &filePath, int sig)
{
QString executable = filePath;
return QString::fromLatin1("for PID in $(ps -f -o pid,comm | grep %1 | awk '/%1/ {print $1}'); "
"do "
"kill -%2 $PID; "
"done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(sig);
}
QString BlackBerryDeviceProcessSignalOperation::killProcessByNameCommandLine(const QString &filePath) const
{
return QString::fromLatin1("%1; %2").arg(signalProcessByNameQnxCommandLine(filePath, 15),
signalProcessByNameQnxCommandLine(filePath, 9));
}
QString BlackBerryDeviceProcessSignalOperation::interruptProcessByNameCommandLine(const QString &filePath) const
{
return signalProcessByNameQnxCommandLine(filePath, 2);
}

View File

@@ -29,22 +29,41 @@
**
****************************************************************************/
#ifndef QNX_INTERNAL_BLACKBERRYDEVICEPROCESSSUPPORT_H
#define QNX_INTERNAL_BLACKBERRYDEVICEPROCESSSUPPORT_H
#ifndef QNXDEVICEPROCESSSIGNALOPERATION_H
#define QNXDEVICEPROCESSSIGNALOPERATION_H
#include <remotelinux/linuxdevice.h>
#include <remotelinux/remotelinuxsignaloperation.h>
namespace Qnx {
namespace Internal {
class BlackBerryDeviceProcessSupport : public RemoteLinux::LinuxDeviceProcessSupport
class QnxDeviceProcessSignalOperation : public RemoteLinux::RemoteLinuxSignalOperation
{
public:
Q_OBJECT
protected:
explicit QnxDeviceProcessSignalOperation(const QSsh::SshConnectionParameters sshParameters);
private:
QString killProcessByNameCommandLine(const QString &filePath) const;
QString interruptProcessByNameCommandLine(const QString &filePath) const;
friend class QnxDeviceConfiguration;
};
class BlackBerryDeviceProcessSignalOperation : public RemoteLinux::RemoteLinuxSignalOperation
{
Q_OBJECT
protected:
explicit BlackBerryDeviceProcessSignalOperation(const QSsh::SshConnectionParameters sshParameters);
private:
QString killProcessByNameCommandLine(const QString &filePath) const;
QString interruptProcessByNameCommandLine(const QString &filePath) const;
friend class BlackBerryDeviceConfiguration;
};
} // namespace Internal
} // namespace Qnx
#endif // QNX_INTERNAL_BLACKBERRYDEVICEPROCESSSUPPORT_H
#endif // QNXDEVICEPROCESSSIGNALOPERATION_H

View File

@@ -34,11 +34,15 @@
#include "linuxdevicetester.h"
#include "publickeydeploymentdialog.h"
#include "remotelinux_constants.h"
#include "remotelinuxsignaloperation.h"
#include <coreplugin/id.h>
#include <projectexplorer/devicesupport/sshdeviceprocesslist.h>
#include <ssh/sshremoteprocessrunner.h>
#include <utils/qtcassert.h>
#include <QTimer>
using namespace ProjectExplorer;
namespace RemoteLinux {
@@ -117,35 +121,6 @@ private:
}
};
QString LinuxDeviceProcessSupport::killProcessByPidCommandLine(int pid) const
{
return QLatin1String("kill -9 ") + QString::number(pid);
}
static QString signalProcessByNameCommandLine(const QString &filePath, int signal)
{
return QString::fromLatin1("cd /proc; for pid in `ls -d [0123456789]*`; "
"do "
"if [ \"`readlink /proc/$pid/exe`\" = \"%1\" ]; then "
" kill %2 $pid;"
"fi; "
"done").arg(filePath).arg(signal);
}
QString LinuxDeviceProcessSupport::killProcessByNameCommandLine(const QString &filePath) const
{
return QString::fromLatin1("%1; %2").arg(signalProcessByNameCommandLine(filePath, 15),
signalProcessByNameCommandLine(filePath, 9));
}
QString LinuxDeviceProcessSupport::interruptProcessByNameCommandLine(const QString &filePath) const
{
return signalProcessByNameCommandLine(filePath, 2);
}
class LinuxPortsGatheringMethod : public ProjectExplorer::PortsGatheringMethod
{
QByteArray commandLine(QAbstractSocket::NetworkLayerProtocol protocol) const
@@ -252,11 +227,6 @@ ProjectExplorer::IDevice::Ptr LinuxDevice::clone() const
return Ptr(new LinuxDevice(*this));
}
DeviceProcessSupport::Ptr LinuxDevice::processSupport() const
{
return DeviceProcessSupport::Ptr(new LinuxDeviceProcessSupport);
}
DeviceProcess *LinuxDevice::createProcess(QObject *parent) const
{
return new LinuxDeviceProcess(sharedFromThis(), parent);
@@ -282,4 +252,9 @@ DeviceTester *LinuxDevice::createDeviceTester() const
return new GenericLinuxDeviceTester;
}
DeviceProcessSignalOperation::Ptr LinuxDevice::signalOperation() const
{
return DeviceProcessSignalOperation::Ptr(new RemoteLinuxSignalOperation(sshParameters()));
}
} // namespace RemoteLinux

View File

@@ -42,14 +42,6 @@ namespace Utils { class PortList; }
namespace RemoteLinux {
namespace Internal { class LinuxDevicePrivate; }
class REMOTELINUX_EXPORT LinuxDeviceProcessSupport : public ProjectExplorer::DeviceProcessSupport
{
public:
QString killProcessByPidCommandLine(int pid) const;
QString killProcessByNameCommandLine(const QString &filePath) const;
QString interruptProcessByNameCommandLine(const QString &filePath) const;
};
class REMOTELINUX_EXPORT LinuxDevice : public ProjectExplorer::IDevice
{
Q_DECLARE_TR_FUNCTIONS(RemoteLinux::Internal::LinuxDevice)
@@ -69,7 +61,6 @@ public:
void executeAction(Core::Id actionId, QWidget *parent);
ProjectExplorer::IDevice::Ptr clone() const;
ProjectExplorer::DeviceProcessSupport::Ptr processSupport() const;
bool canCreateProcess() const { return true; }
ProjectExplorer::DeviceProcess *createProcess(QObject *parent) const;
bool canAutoDetectPorts() const;
@@ -78,6 +69,7 @@ public:
ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const;
bool hasDeviceTester() const { return true; }
ProjectExplorer::DeviceTester *createDeviceTester() const;
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const;
protected:
LinuxDevice() {}

View File

@@ -48,7 +48,8 @@ HEADERS += \
remotelinuxdeploymentdatamodel.h \
remotelinuxanalyzesupport.h \
abstractremotelinuxrunsupport.h \
linuxdeviceprocess.h
linuxdeviceprocess.h \
remotelinuxsignaloperation.h
SOURCES += \
embeddedlinuxqtversion.cpp \
@@ -94,7 +95,8 @@ SOURCES += \
remotelinuxdeploymentdatamodel.cpp \
remotelinuxanalyzesupport.cpp \
abstractremotelinuxrunsupport.cpp \
linuxdeviceprocess.cpp
linuxdeviceprocess.cpp \
remotelinuxsignaloperation.cpp
FORMS += \
genericlinuxdeviceconfigurationwizardsetuppage.ui \

View File

@@ -100,6 +100,8 @@ QtcPlugin {
"remotelinuxruncontrol.h",
"remotelinuxruncontrolfactory.cpp",
"remotelinuxruncontrolfactory.h",
"remotelinuxsignaloperation.cpp",
"remotelinuxsignaloperation.h",
"remotelinuxutils.cpp",
"remotelinuxutils.h",
"sshkeydeployer.cpp",

View File

@@ -0,0 +1,133 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "remotelinuxsignaloperation.h"
#include <ssh/sshremoteprocessrunner.h>
#include <ssh/sshconnection.h>
#include <utils/qtcassert.h>
using namespace RemoteLinux;
using namespace ProjectExplorer;
RemoteLinuxSignalOperation::RemoteLinuxSignalOperation(
const QSsh::SshConnectionParameters sshParameters)
: DeviceProcessSignalOperation()
, m_sshParameters(sshParameters)
, m_runner(0)
{}
RemoteLinuxSignalOperation::~RemoteLinuxSignalOperation()
{
if (m_runner) {
connect(m_runner, SIGNAL(processClosed(int)), m_runner, SLOT(deleteLater()));
connect(m_runner, SIGNAL(connectionError()), m_runner, SLOT(deleteLater()));
}
}
static QString signalProcessByPidCommandLine(int pid, int signal)
{
return QString::fromLatin1("kill -%1 %2").arg(signal).arg(pid);
}
void RemoteLinuxSignalOperation::run(const QString command)
{
QTC_ASSERT(!m_runner, return);
m_runner = new QSsh::SshRemoteProcessRunner();
connect(m_runner, SIGNAL(processClosed(int)), SLOT(runnerProcessFinished()));
connect(m_runner, SIGNAL(connectionError()), SLOT(runnerConnectionError()));
m_runner->run(command.toLatin1(), m_sshParameters);
}
void RemoteLinuxSignalOperation::finish()
{
delete m_runner;
m_runner = 0;
emit finished(m_errorMessage);
}
static QString signalProcessByNameCommandLine(const QString &filePath, int signal)
{
return QString::fromLatin1(
"cd /proc; for pid in `ls -d [0123456789]*`; "
"do "
"if [ \"`readlink /proc/$pid/exe`\" = \"%1\" ]; then "
" kill %2 $pid;"
"fi; "
"done").arg(filePath).arg(signal);
}
QString RemoteLinuxSignalOperation::killProcessByNameCommandLine(const QString &filePath) const
{
return QString::fromLatin1("%1; %2").arg(signalProcessByNameCommandLine(filePath, 15),
signalProcessByNameCommandLine(filePath, 9));
}
QString RemoteLinuxSignalOperation::interruptProcessByNameCommandLine(const QString &filePath) const
{
return signalProcessByNameCommandLine(filePath, 2);
}
void RemoteLinuxSignalOperation::killProcess(int pid)
{
run(signalProcessByPidCommandLine(pid, 9));
}
void RemoteLinuxSignalOperation::killProcess(const QString &filePath)
{
run(killProcessByNameCommandLine(filePath));
}
void RemoteLinuxSignalOperation::interruptProcess(int pid)
{
run(signalProcessByPidCommandLine(pid, 2));
}
void RemoteLinuxSignalOperation::interruptProcess(const QString &filePath)
{
run(interruptProcessByNameCommandLine(filePath));
}
void RemoteLinuxSignalOperation::runnerProcessFinished()
{
m_errorMessage.clear();
if (m_runner->processExitStatus() != QSsh::SshRemoteProcess::NormalExit) {
m_errorMessage = m_runner->processErrorString();
} else if (m_runner->processExitCode() != 0) {
m_errorMessage = tr("Exit code is %1. stderr: ").arg(m_runner->processExitCode())
+ QString::fromLatin1(m_runner->readAllStandardError());
}
finish();
}
void RemoteLinuxSignalOperation::runnerConnectionError()
{
m_errorMessage = m_runner->lastConnectionErrorString();
finish();
}

View File

@@ -0,0 +1,78 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef REMOTELINUXSIGNALOPERATION_H
#define REMOTELINUXSIGNALOPERATION_H
#include "remotelinux_export.h"
#include <projectexplorer/devicesupport/idevice.h>
#include <ssh/sshconnection.h>
namespace QSsh {
class SshConnectionParameters;
class SshRemoteProcessRunner;
}
namespace RemoteLinux {
class REMOTELINUX_EXPORT RemoteLinuxSignalOperation
: public ProjectExplorer::DeviceProcessSignalOperation
{
Q_OBJECT
public:
virtual ~RemoteLinuxSignalOperation();
void killProcess(int pid);
void killProcess(const QString &filePath);
void interruptProcess(int pid);
void interruptProcess(const QString &filePath);
protected:
RemoteLinuxSignalOperation(const QSsh::SshConnectionParameters sshParameters);
private slots:
void runnerProcessFinished();
void runnerConnectionError();
private:
virtual QString killProcessByNameCommandLine(const QString &filePath) const;
virtual QString interruptProcessByNameCommandLine(const QString &filePath) const;
void run(const QString command);
void finish();
const QSsh::SshConnectionParameters m_sshParameters;
QSsh::SshRemoteProcessRunner *m_runner;
friend class LinuxDevice;
};
}
#endif // REMOTELINUXSIGNALOPERATION_H