summaryrefslogtreecommitdiff
path: root/src/libs/utils/consoleprocess_unix.cpp
diff options
context:
space:
mode:
authorFawzi Mohamed <fawzi.mohamed@digia.com>2012-12-19 19:04:36 +0100
committerFawzi Mohamed <fawzi.mohamed@digia.com>2013-01-29 17:56:59 +0100
commit18fa486531a0cb274d67279e04f0b18ff6ee82e3 (patch)
tree753ab71ef145950882d194ba618fbd5f4d737c40 /src/libs/utils/consoleprocess_unix.cpp
parent7db3b660b64d5d6fa35b067e148d6807a089b209 (diff)
downloadqt-creator-18fa486531a0cb274d67279e04f0b18ff6ee82e3.tar.gz
consoleprocess: support Terminal.app on mac
Distinguishes the process that starts the terminal from the stub process, as on mac to support Terminal.app they are different. Handle the stub not through the process that starts the terminal, but through the local socket (on *nix). Replace the blocking wait(...) in the main thread, with a nonblocking wait in the signal handler when receiving a SIGCHLD, to leave the main thread able to handle communication with creator. This change allows the use of terminal emulator commands that share a single instance or that fork. So this is also the real fix for QTCREATORBUG-1633 on linux. If creator crashes the stub and the debugged program live on. This was done on purpose, it could be changed if considered better. Task-number: QTCREATORBUG-6371 Task-number: QTCREATORBUG-1633 Change-Id: I4d4fb3a67b1987f4e46e2c603dcefe8c15152ad2 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com>
Diffstat (limited to 'src/libs/utils/consoleprocess_unix.cpp')
-rw-r--r--src/libs/utils/consoleprocess_unix.cpp92
1 files changed, 70 insertions, 22 deletions
diff --git a/src/libs/utils/consoleprocess_unix.cpp b/src/libs/utils/consoleprocess_unix.cpp
index a8ba73debc..7190230fe7 100644
--- a/src/libs/utils/consoleprocess_unix.cpp
+++ b/src/libs/utils/consoleprocess_unix.cpp
@@ -37,6 +37,7 @@
#include <QCoreApplication>
#include <QDir>
#include <QSettings>
+#include <QTimer>
#include <sys/stat.h>
#include <sys/types.h>
@@ -51,7 +52,10 @@ ConsoleProcessPrivate::ConsoleProcessPrivate() :
m_appPid(0),
m_stubSocket(0),
m_tempFile(0),
- m_settings(0)
+ m_settings(0),
+ m_stubConnected(false),
+ m_stubPid(0),
+ m_stubConnectTimer(0)
{
}
@@ -61,8 +65,6 @@ ConsoleProcess::ConsoleProcess(QObject *parent) :
connect(&d->m_stubServer, SIGNAL(newConnection()), SLOT(stubConnectionAvailable()));
d->m_process.setProcessChannelMode(QProcess::ForwardedChannels);
- connect(&d->m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
- SLOT(stubExited()));
}
void ConsoleProcess::setSettings(QSettings *settings)
@@ -159,21 +161,54 @@ bool ConsoleProcess::start(const QString &program, const QString &args)
d->m_tempFile = 0;
return false;
}
+ d->m_stubConnectTimer = new QTimer(this);
+ connect(d->m_stubConnectTimer, SIGNAL(timeout()), SLOT(stop()));
+ d->m_stubConnectTimer->setSingleShot(true);
+ d->m_stubConnectTimer->start(10000);
d->m_executable = program;
- emit wrapperStarted();
return true;
}
-void ConsoleProcess::stop()
+void ConsoleProcess::killProcess()
{
- if (!isRunning())
- return;
- stubServerShutdown();
+ if (d->m_stubSocket && d->m_stubSocket->isWritable()) {
+ d->m_stubSocket->write("k", 1);
+ d->m_stubSocket->flush();
+ }
d->m_appPid = 0;
- d->m_process.terminate();
- if (!d->m_process.waitForFinished(1000))
- d->m_process.kill();
- d->m_process.waitForFinished();
+}
+
+void ConsoleProcess::killStub()
+{
+ if (d->m_stubSocket && d->m_stubSocket->isWritable()) {
+ d->m_stubSocket->write("s", 1);
+ d->m_stubSocket->flush();
+ }
+ stubServerShutdown();
+ d->m_stubPid = 0;
+}
+
+void ConsoleProcess::detachStub()
+{
+ if (d->m_stubSocket && d->m_stubSocket->isWritable()) {
+ d->m_stubSocket->write("d", 1);
+ d->m_stubSocket->flush();
+ }
+ stubServerShutdown();
+ d->m_stubPid = 0;
+}
+
+void ConsoleProcess::stop()
+{
+ killProcess();
+ killStub();
+ if (isRunning()) {
+ d->m_process.terminate();
+ if (!d->m_process.waitForFinished(1000)) {
+ d->m_process.kill();
+ d->m_process.waitForFinished();
+ }
+ }
}
bool ConsoleProcess::isRunning() const
@@ -210,7 +245,8 @@ QString ConsoleProcess::stubServerListen()
void ConsoleProcess::stubServerShutdown()
{
- delete d->m_stubSocket;
+ if (d->m_stubSocket)
+ d->m_stubSocket->deleteLater(); // we might be called from the disconnected signal of m_stubSocket
d->m_stubSocket = 0;
if (d->m_stubServer.isListening()) {
d->m_stubServer.close();
@@ -220,8 +256,15 @@ void ConsoleProcess::stubServerShutdown()
void ConsoleProcess::stubConnectionAvailable()
{
+ if (d->m_stubConnectTimer) {
+ delete d->m_stubConnectTimer;
+ d->m_stubConnectTimer = 0;
+ }
+ d->m_stubConnected = true;
+ emit stubStarted();
d->m_stubSocket = d->m_stubServer.nextPendingConnection();
connect(d->m_stubSocket, SIGNAL(readyRead()), SLOT(readStubOutput()));
+ connect(d->m_stubSocket, SIGNAL(disconnected()), SLOT(stubExited()));
}
static QString errorMsg(int code)
@@ -238,11 +281,12 @@ void ConsoleProcess::readStubOutput()
emit processError(msgCannotChangeToWorkDir(workingDirectory(), errorMsg(out.mid(10).toInt())));
} else if (out.startsWith("err:exec ")) {
emit processError(msgCannotExecute(d->m_executable, errorMsg(out.mid(9).toInt())));
- } else if (out.startsWith("pid ")) {
- // Will not need it any more
+ } else if (out.startsWith("spid ")) {
delete d->m_tempFile;
d->m_tempFile = 0;
+ d->m_stubPid = out.mid(4).toInt();
+ } else if (out.startsWith("pid ")) {
d->m_appPid = out.mid(4).toInt();
emit processStarted();
} else if (out.startsWith("exit ")) {
@@ -257,6 +301,7 @@ void ConsoleProcess::readStubOutput()
emit processStopped();
} else {
emit processError(msgUnexpectedOutput(out));
+ d->m_stubPid = 0;
d->m_process.terminate();
break;
}
@@ -269,6 +314,7 @@ void ConsoleProcess::stubExited()
if (d->m_stubSocket && d->m_stubSocket->state() == QLocalSocket::ConnectedState)
d->m_stubSocket->waitForDisconnected();
stubServerShutdown();
+ d->m_stubPid = 0;
delete d->m_tempFile;
d->m_tempFile = 0;
if (d->m_appPid) {
@@ -277,7 +323,7 @@ void ConsoleProcess::stubExited()
d->m_appPid = 0;
emit processStopped(); // Maybe it actually did not, but keep state consistent
}
- emit wrapperStopped();
+ emit stubStopped();
}
struct Terminal {
@@ -293,15 +339,18 @@ static const Terminal knownTerminals[] =
{"rxvt", "-e"},
{"urxvt", "-e"},
{"xfce4-terminal", "-x"},
- {"konsole", "--nofork -e"},
+ {"konsole", "-e"},
{"gnome-terminal", "-x"}
};
QString ConsoleProcess::defaultTerminalEmulator()
{
- if (Utils::HostOsInfo::isMacHost())
+ if (Utils::HostOsInfo::isMacHost()) {
+ QString termCmd = QCoreApplication::applicationDirPath() + QLatin1String("/../Resources/scripts/openTerminal.command");
+ if (QFile(termCmd).exists())
+ return termCmd.replace(QLatin1Char(' '), QLatin1String("\\ "));
return QLatin1String("/usr/X11/bin/xterm");
-
+ }
const Environment env = Environment::systemEnvironment();
const int terminalCount = int(sizeof(knownTerminals) / sizeof(knownTerminals[0]));
for (int i = 0; i < terminalCount; ++i) {
@@ -317,9 +366,6 @@ QString ConsoleProcess::defaultTerminalEmulator()
QStringList ConsoleProcess::availableTerminalEmulators()
{
- if (Utils::HostOsInfo::isMacHost())
- return QStringList(defaultTerminalEmulator());
-
QStringList result;
const Environment env = Environment::systemEnvironment();
const int terminalCount = int(sizeof(knownTerminals) / sizeof(knownTerminals[0]));
@@ -331,6 +377,8 @@ QStringList ConsoleProcess::availableTerminalEmulators()
result.push_back(terminal);
}
}
+ if (!result.contains(defaultTerminalEmulator()))
+ result.append(defaultTerminalEmulator());
result.sort();
return result;
}