LP-311 Remove basic/advanced stabilization tab auto-switch (autotune/txpid lock issues)
[librepilot.git] / ground / gcs / src / libs / utils / consoleprocess_win.cpp
bloba4a6bfb9d87b32103823ca5d480d43ca9e80dcac
1 /**
2 ******************************************************************************
4 * @file consoleprocess_win.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
7 * @brief
8 * @see The GNU Public License (GPL) Version 3
9 * @defgroup
10 * @{
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "consoleprocess.h"
30 #include "winutils.h"
32 #include <QtCore/QCoreApplication>
33 #include <QtCore/QDir>
34 #include <QtCore/QTemporaryFile>
35 #include <QtCore/QAbstractEventDispatcher>
36 #include "qwineventnotifier_p.h"
38 #include <QtNetwork/QLocalSocket>
40 #include <stdlib.h>
42 using namespace Utils;
44 ConsoleProcess::ConsoleProcess(QObject *parent) :
45 QObject(parent),
46 m_mode(Run),
47 m_appPid(0),
48 m_stubSocket(0),
49 m_tempFile(0),
50 m_pid(0),
51 m_hInferior(NULL),
52 inferiorFinishedNotifier(0),
53 processFinishedNotifier(0)
55 connect(&m_stubServer, SIGNAL(newConnection()), SLOT(stubConnectionAvailable()));
58 ConsoleProcess::~ConsoleProcess()
60 stop();
63 bool ConsoleProcess::start(const QString &program, const QStringList &args)
65 if (isRunning()) {
66 return false;
69 const QString err = stubServerListen();
70 if (!err.isEmpty()) {
71 emit processError(msgCommChannelFailed(err));
72 return false;
75 if (!environment().isEmpty()) {
76 m_tempFile = new QTemporaryFile();
77 if (!m_tempFile->open()) {
78 stubServerShutdown();
79 emit processError(msgCannotCreateTempFile(m_tempFile->errorString()));
80 delete m_tempFile;
81 m_tempFile = 0;
82 return false;
84 QTextStream out(m_tempFile);
85 out.setCodec("UTF-16LE");
86 out.setGenerateByteOrderMark(false);
87 foreach(const QString &var, fixWinEnvironment(environment()))
88 out << var << QChar(0);
89 out << QChar(0);
92 STARTUPINFO si;
93 ZeroMemory(&si, sizeof(si));
94 si.cb = sizeof(si);
96 m_pid = new PROCESS_INFORMATION;
97 ZeroMemory(m_pid, sizeof(PROCESS_INFORMATION));
99 QString workDir = QDir::toNativeSeparators(workingDirectory());
100 if (!workDir.isEmpty() && !workDir.endsWith('\\')) {
101 workDir.append('\\');
104 QStringList stubArgs;
105 stubArgs << modeOption(m_mode)
106 << m_stubServer.fullServerName()
107 << workDir
108 << (m_tempFile ? m_tempFile->fileName() : 0)
109 << createWinCommandline(program, args)
110 << msgPromptToClose();
112 const QString cmdLine = createWinCommandline(
113 QCoreApplication::applicationDirPath() + QLatin1String("/qtcreator_process_stub.exe"), stubArgs);
115 bool success = CreateProcessW(0, (WCHAR *)cmdLine.utf16(),
116 0, 0, FALSE, CREATE_NEW_CONSOLE,
117 0, 0,
118 &si, m_pid);
120 if (!success) {
121 delete m_pid;
122 m_pid = 0;
123 delete m_tempFile;
124 m_tempFile = 0;
125 stubServerShutdown();
126 emit processError(tr("The process '%1' could not be started: %2").arg(cmdLine, winErrorMessage(GetLastError())));
127 return false;
130 processFinishedNotifier = new QWinEventNotifier(m_pid->hProcess, this);
131 connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), SLOT(stubExited()));
132 emit wrapperStarted();
133 return true;
136 void ConsoleProcess::stop()
138 if (m_hInferior != NULL) {
139 TerminateProcess(m_hInferior, (unsigned)-1);
140 cleanupInferior();
142 if (m_pid) {
143 TerminateProcess(m_pid->hProcess, (unsigned)-1);
144 WaitForSingleObject(m_pid->hProcess, INFINITE);
145 cleanupStub();
149 bool ConsoleProcess::isRunning() const
151 return m_pid != 0;
154 QString ConsoleProcess::stubServerListen()
156 if (m_stubServer.listen(QString::fromLatin1("creator-%1-%2")
157 .arg(QCoreApplication::applicationPid())
158 .arg(rand()))) {
159 return QString();
161 return m_stubServer.errorString();
164 void ConsoleProcess::stubServerShutdown()
166 delete m_stubSocket;
167 m_stubSocket = 0;
168 if (m_stubServer.isListening()) {
169 m_stubServer.close();
173 void ConsoleProcess::stubConnectionAvailable()
175 m_stubSocket = m_stubServer.nextPendingConnection();
176 connect(m_stubSocket, SIGNAL(readyRead()), SLOT(readStubOutput()));
179 void ConsoleProcess::readStubOutput()
181 while (m_stubSocket->canReadLine()) {
182 QByteArray out = m_stubSocket->readLine();
183 out.chop(2); // \r\n
184 if (out.startsWith("err:chdir ")) {
185 emit processError(msgCannotChangeToWorkDir(workingDirectory(), winErrorMessage(out.mid(10).toInt())));
186 } else if (out.startsWith("err:exec ")) {
187 emit processError(msgCannotExecute(m_executable, winErrorMessage(out.mid(9).toInt())));
188 } else if (out.startsWith("pid ")) {
189 // Wil not need it any more
190 delete m_tempFile;
191 m_tempFile = 0;
193 m_appPid = out.mid(4).toInt();
194 m_hInferior = OpenProcess(
195 SYNCHRONIZE | PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE,
196 FALSE, m_appPid);
197 if (m_hInferior == NULL) {
198 emit processError(tr("Cannot obtain a handle to the inferior: %1")
199 .arg(winErrorMessage(GetLastError())));
200 // Uhm, and now what?
201 continue;
203 inferiorFinishedNotifier = new QWinEventNotifier(m_hInferior, this);
204 connect(inferiorFinishedNotifier, SIGNAL(activated(HANDLE)), SLOT(inferiorExited()));
205 emit processStarted();
206 } else {
207 emit processError(msgUnexpectedOutput());
208 TerminateProcess(m_pid->hProcess, (unsigned)-1);
209 break;
214 void ConsoleProcess::cleanupInferior()
216 delete inferiorFinishedNotifier;
217 inferiorFinishedNotifier = 0;
218 CloseHandle(m_hInferior);
219 m_hInferior = NULL;
220 m_appPid = 0;
223 void ConsoleProcess::inferiorExited()
225 DWORD chldStatus;
227 if (!GetExitCodeProcess(m_hInferior, &chldStatus)) {
228 emit processError(tr("Cannot obtain exit status from inferior: %1")
229 .arg(winErrorMessage(GetLastError())));
231 cleanupInferior();
232 m_appStatus = QProcess::NormalExit;
233 m_appCode = chldStatus;
234 emit processStopped();
237 void ConsoleProcess::cleanupStub()
239 stubServerShutdown();
240 delete processFinishedNotifier;
241 processFinishedNotifier = 0;
242 CloseHandle(m_pid->hThread);
243 CloseHandle(m_pid->hProcess);
244 delete m_pid;
245 m_pid = 0;
246 delete m_tempFile;
247 m_tempFile = 0;
250 void ConsoleProcess::stubExited()
252 // The stub exit might get noticed before we read the pid for the kill.
253 if (m_stubSocket && m_stubSocket->state() == QLocalSocket::ConnectedState) {
254 m_stubSocket->waitForDisconnected();
256 cleanupStub();
257 if (m_hInferior != NULL) {
258 TerminateProcess(m_hInferior, (unsigned)-1);
259 cleanupInferior();
260 m_appStatus = QProcess::CrashExit;
261 m_appCode = -1;
262 emit processStopped();
264 emit wrapperStopped();