diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 374b4ad3a1b..8fd3d94e2d3 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -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)); diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index eda23a5dac1..1c08bca8696 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -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; diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 7c9481cf3fd..343032ea1b2 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -32,6 +32,7 @@ #include "deviceprocesslist.h" #include "localprocesslist.h" #include "desktopdeviceconfigurationwidget.h" +#include "desktopprocesssignaloperation.h" #include #include @@ -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)); diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.h b/src/plugins/projectexplorer/devicesupport/desktopdevice.h index 7ddd35bacc7..1b65f6c49b5 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.h @@ -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; diff --git a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp index b3cc471f505..eb7f3b4f650 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp @@ -28,13 +28,11 @@ ****************************************************************************/ #include "desktopdeviceprocess.h" +#include "idevice.h" #include #include - -#ifdef Q_OS_UNIX -#include -#endif +#include 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() diff --git a/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp new file mode 100644 index 00000000000..364eaf1f4ad --- /dev/null +++ b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp @@ -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 + +#include + +#ifdef Q_OS_WIN +#define _WIN32_WINNT 0x0502 +#include +#ifndef PROCESS_SUSPEND_RESUME +#define PROCESS_SUSPEND_RESUME 0x0800 +#endif // PROCESS_SUSPEND_RESUME +#else // Q_OS_WIN +#include +#include +#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 diff --git a/src/plugins/qnx/blackberrydeviceprocesssupport.cpp b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.h similarity index 51% rename from src/plugins/qnx/blackberrydeviceprocesssupport.cpp rename to src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.h index 2acce3e5fe6..b6d61f220b7 100644 --- a/src/plugins/qnx/blackberrydeviceprocesssupport.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.h @@ -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 -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 diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index 5ab8e545473..81328e8f115 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -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() diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index d4ebaf979d9..81a819b7e28 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -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(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 8291a6c0091..3da578b90e4 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -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 Ptr; + ~DeviceProcessSignalOperation() {} + typedef QSharedPointer 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; diff --git a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp index 291f006ca75..963895b4a72 100644 --- a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp +++ b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp @@ -51,9 +51,6 @@ #include #include #include -#ifndef PROCESS_SUSPEND_RESUME -#define PROCESS_SUSPEND_RESUME 0x0800 -#endif #endif namespace ProjectExplorer { @@ -125,28 +122,8 @@ QList 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 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 diff --git a/src/plugins/projectexplorer/devicesupport/localprocesslist.h b/src/plugins/projectexplorer/devicesupport/localprocesslist.h index c1d097ab17a..8588065ca82 100644 --- a/src/plugins/projectexplorer/devicesupport/localprocesslist.h +++ b/src/plugins/projectexplorer/devicesupport/localprocesslist.h @@ -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 diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp index ae9e6614894..af738701d59 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp @@ -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; } diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp index 56fcbde45ed..1970c588c71 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp @@ -28,6 +28,8 @@ ****************************************************************************/ #include "sshdeviceprocesslist.h" +#include "idevice.h" + #include #include @@ -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) { + if (errorString.isEmpty()) + reportProcessKilled(); + else + reportError(tr("Error: Kill process failed: %1").arg(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) - 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"); - } } 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 diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h index 4e233aeb868..62d5548f950 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h @@ -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; diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index ea124bcf4c7..44009c2c53d 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -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 \ diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 7b9ba5a07d7..3fd7a478556 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -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" ] } diff --git a/src/plugins/qnx/blackberrydeviceconfiguration.cpp b/src/plugins/qnx/blackberrydeviceconfiguration.cpp index ace022255c0..f3bd8a7024b 100644 --- a/src/plugins/qnx/blackberrydeviceconfiguration.cpp +++ b/src/plugins/qnx/blackberrydeviceconfiguration.cpp @@ -32,11 +32,12 @@ #include "blackberrydeviceconfiguration.h" #include "qnxconstants.h" +#include "qnxdeviceprocesssignaloperation.h" #include "blackberrydeviceconfigurationwidget.h" #include "blackberrydeviceconnectionmanager.h" -#include "blackberrydeviceprocesssupport.h" #include +#include using namespace Qnx; using namespace Qnx::Internal; @@ -111,11 +112,6 @@ BlackBerryDeviceConfiguration::ConstPtr BlackBerryDeviceConfiguration::device(co return dev.dynamicCast(); } -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())); +} diff --git a/src/plugins/qnx/blackberrydeviceconfiguration.h b/src/plugins/qnx/blackberrydeviceconfiguration.h index 950233637c7..95b58988e50 100644 --- a/src/plugins/qnx/blackberrydeviceconfiguration.h +++ b/src/plugins/qnx/blackberrydeviceconfiguration.h @@ -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, diff --git a/src/plugins/qnx/blackberrylogprocessrunner.cpp b/src/plugins/qnx/blackberrylogprocessrunner.cpp index e324899561b..ecd627998a4 100644 --- a/src/plugins/qnx/blackberrylogprocessrunner.cpp +++ b/src/plugins/qnx/blackberrylogprocessrunner.cpp @@ -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(); diff --git a/src/plugins/qnx/qnx.pro b/src/plugins/qnx/qnx.pro index fa67ae8d405..ed664b364e7 100644 --- a/src/plugins/qnx/qnx.pro +++ b/src/plugins/qnx/qnx.pro @@ -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 \ diff --git a/src/plugins/qnx/qnx.qbs b/src/plugins/qnx/qnx.qbs index 39a0c59885c..6bfc3e2f1ae 100644 --- a/src/plugins/qnx/qnx.qbs +++ b/src/plugins/qnx/qnx.qbs @@ -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", diff --git a/src/plugins/qnx/qnxdeviceconfiguration.cpp b/src/plugins/qnx/qnxdeviceconfiguration.cpp index 2f9a5a2571d..cdaea98b345 100644 --- a/src/plugins/qnx/qnxdeviceconfiguration.cpp +++ b/src/plugins/qnx/qnxdeviceconfiguration.cpp @@ -31,8 +31,10 @@ #include "qnxdeviceconfiguration.h" #include "qnxdevicetester.h" +#include "qnxdeviceprocesssignaloperation.h" #include +#include #include #include @@ -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())); +} diff --git a/src/plugins/qnx/qnxdeviceconfiguration.h b/src/plugins/qnx/qnxdeviceconfiguration.h index 5f0ccd9d958..bf713a0f927 100644 --- a/src/plugins/qnx/qnxdeviceconfiguration.h +++ b/src/plugins/qnx/qnxdeviceconfiguration.h @@ -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 diff --git a/src/plugins/qnx/qnxdeviceprocesssignaloperation.cpp b/src/plugins/qnx/qnxdeviceprocesssignaloperation.cpp new file mode 100644 index 00000000000..afbb79d125d --- /dev/null +++ b/src/plugins/qnx/qnxdeviceprocesssignaloperation.cpp @@ -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); +} diff --git a/src/plugins/qnx/blackberrydeviceprocesssupport.h b/src/plugins/qnx/qnxdeviceprocesssignaloperation.h similarity index 66% rename from src/plugins/qnx/blackberrydeviceprocesssupport.h rename to src/plugins/qnx/qnxdeviceprocesssignaloperation.h index 656df0c1f1a..a3e86c8ad27 100644 --- a/src/plugins/qnx/blackberrydeviceprocesssupport.h +++ b/src/plugins/qnx/qnxdeviceprocesssignaloperation.h @@ -29,22 +29,41 @@ ** ****************************************************************************/ -#ifndef QNX_INTERNAL_BLACKBERRYDEVICEPROCESSSUPPORT_H -#define QNX_INTERNAL_BLACKBERRYDEVICEPROCESSSUPPORT_H +#ifndef QNXDEVICEPROCESSSIGNALOPERATION_H +#define QNXDEVICEPROCESSSIGNALOPERATION_H -#include +#include 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 diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 5d707b23545..b68f6c0c9cc 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -34,11 +34,15 @@ #include "linuxdevicetester.h" #include "publickeydeploymentdialog.h" #include "remotelinux_constants.h" +#include "remotelinuxsignaloperation.h" #include #include +#include #include +#include + 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 diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index f19a2476b2d..8f9d9b1c643 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -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() {} diff --git a/src/plugins/remotelinux/remotelinux.pro b/src/plugins/remotelinux/remotelinux.pro index 8c4453cabb3..b6d76fc30ff 100644 --- a/src/plugins/remotelinux/remotelinux.pro +++ b/src/plugins/remotelinux/remotelinux.pro @@ -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 \ diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs index cb610ef7a66..536e9bfcc84 100644 --- a/src/plugins/remotelinux/remotelinux.qbs +++ b/src/plugins/remotelinux/remotelinux.qbs @@ -100,6 +100,8 @@ QtcPlugin { "remotelinuxruncontrol.h", "remotelinuxruncontrolfactory.cpp", "remotelinuxruncontrolfactory.h", + "remotelinuxsignaloperation.cpp", + "remotelinuxsignaloperation.h", "remotelinuxutils.cpp", "remotelinuxutils.h", "sshkeydeployer.cpp", diff --git a/src/plugins/remotelinux/remotelinuxsignaloperation.cpp b/src/plugins/remotelinux/remotelinuxsignaloperation.cpp new file mode 100644 index 00000000000..bdfb67a787e --- /dev/null +++ b/src/plugins/remotelinux/remotelinuxsignaloperation.cpp @@ -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 +#include +#include + +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(); +} diff --git a/src/plugins/remotelinux/remotelinuxsignaloperation.h b/src/plugins/remotelinux/remotelinuxsignaloperation.h new file mode 100644 index 00000000000..4e2d9da94b6 --- /dev/null +++ b/src/plugins/remotelinux/remotelinuxsignaloperation.h @@ -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 +#include + +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