forked from qt-creator/qt-creator
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:
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
90
src/plugins/qnx/qnxdeviceprocesssignaloperation.cpp
Normal file
90
src/plugins/qnx/qnxdeviceprocesssignaloperation.cpp
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -100,6 +100,8 @@ QtcPlugin {
|
||||
"remotelinuxruncontrol.h",
|
||||
"remotelinuxruncontrolfactory.cpp",
|
||||
"remotelinuxruncontrolfactory.h",
|
||||
"remotelinuxsignaloperation.cpp",
|
||||
"remotelinuxsignaloperation.h",
|
||||
"remotelinuxutils.cpp",
|
||||
"remotelinuxutils.h",
|
||||
"sshkeydeployer.cpp",
|
||||
|
||||
133
src/plugins/remotelinux/remotelinuxsignaloperation.cpp
Normal file
133
src/plugins/remotelinux/remotelinuxsignaloperation.cpp
Normal 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();
|
||||
}
|
||||
78
src/plugins/remotelinux/remotelinuxsignaloperation.h
Normal file
78
src/plugins/remotelinux/remotelinuxsignaloperation.h
Normal 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
|
||||
Reference in New Issue
Block a user