diff options
author | Fawzi Mohamed <fawzi.mohamed@digia.com> | 2012-12-19 19:04:36 +0100 |
---|---|---|
committer | Fawzi Mohamed <fawzi.mohamed@digia.com> | 2013-01-29 17:56:59 +0100 |
commit | 18fa486531a0cb274d67279e04f0b18ff6ee82e3 (patch) | |
tree | 753ab71ef145950882d194ba618fbd5f4d737c40 /src/libs/utils/consoleprocess_unix.cpp | |
parent | 7db3b660b64d5d6fa35b067e148d6807a089b209 (diff) | |
download | qt-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.cpp | 92 |
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; } |