20#include "QtCore/qprocess.h"
21#include "QtCore/qstringlist.h"
22#include "QtCore/qhash.h"
23#include "QtCore/qmap.h"
24#include "QtCore/qshareddata.h"
25#include "QtCore/qdeadlinetimer.h"
26#include "private/qiodevice_p.h"
31#include <QtCore/private/qorderedmutexlocker_p.h>
35#include "QtCore/qt_windows.h"
37#define INVALID_Q_PIPE INVALID_HANDLE_VALUE
40#define INVALID_Q_PIPE -1
46class QWindowsPipeReader;
47class QWindowsPipeWriter;
48class QWinEventNotifier;
51class QProcEnvKey :
public QString
55 explicit QProcEnvKey(
const QString &other) : QString(other) {}
56 QProcEnvKey(
const QProcEnvKey &other) : QString(other) {}
57 bool operator==(
const QProcEnvKey &other)
const {
return !compare(other, Qt::CaseInsensitive); }
60inline bool operator<(
const QProcEnvKey &a,
const QProcEnvKey &b)
64 return a.compare(b, Qt::CaseInsensitive) < 0;
67Q_DECLARE_TYPEINFO(QProcEnvKey, Q_RELOCATABLE_TYPE);
69typedef QString QProcEnvValue;
71using QProcEnvKey = QByteArray;
81 return byteValue.isEmpty() && other.byteValue.isEmpty()
82 ? stringValue == other.stringValue
83 : bytes() == other.bytes();
87 if (byteValue.isEmpty() && !stringValue.isEmpty())
88 byteValue = stringValue.toLocal8Bit();
93 if (stringValue.isEmpty() && !byteValue.isEmpty())
94 stringValue = QString::fromLocal8Bit(byteValue);
130 Key &ent = nameMap[name];
132 ent = name.toLocal8Bit();
137 const QString sname = QString::fromLocal8Bit(name);
140 nameMap[sname] = name;
156 nameMap = other.nameMap;
178template<> Q_INLINE_TEMPLATE
void QSharedDataPointer<QProcessEnvironmentPrivate>::detach()
180 if (d && d->ref.loadRelaxed() == 1)
182 QProcessEnvironmentPrivate *x = (d ?
new QProcessEnvironmentPrivate(*d)
183 :
new QProcessEnvironmentPrivate);
185 if (d && !d->ref.deref())
190#if QT_CONFIG(process)
192class QProcessPrivate :
public QIODevicePrivate
195 Q_DECLARE_PUBLIC(QProcess)
198 enum ProcessChannelType :
char {
207 Channel &operator=(
const QString &fileName)
211 type = fileName.isEmpty() ? Normal : Redirect;
215 void pipeTo(QProcessPrivate *other)
222 void pipeFrom(QProcessPrivate *other)
230 QProcessPrivate *process =
nullptr;
232 QSocketNotifier *notifier =
nullptr;
235 QWindowsPipeReader *reader =
nullptr;
236 QWindowsPipeWriter *writer;
239 Q_PIPE pipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
241 ProcessChannelType type = Normal;
247 virtual ~QProcessPrivate();
250 bool _q_canReadStandardOutput();
251 bool _q_canReadStandardError();
253 qint64 pipeWriterBytesToWrite()
const;
254 void _q_bytesWritten(qint64 bytes);
255 void _q_writeFailed();
260 bool _q_startupNotification();
261 void _q_processDied();
263 Channel stdinChannel;
264 Channel stdoutChannel;
265 Channel stderrChannel;
267 bool openChannelsForDetached();
268 bool openChannel(Channel &channel);
269 void closeChannel(Channel *channel);
270 void closeWriteChannel();
271 void closeChannels();
272 bool tryReadFromChannel(Channel *channel);
275 QStringList arguments;
276 QString workingDirectory;
277 QProcessEnvironment environment = QProcessEnvironment::InheritFromParent;
279 QString nativeArguments;
280 QProcess::CreateProcessArgumentModifier modifyCreateProcessArgs;
281 QWinEventNotifier *processFinishedNotifier =
nullptr;
282 Q_PROCESS_INFORMATION *pid =
nullptr;
285 std::function<
void(
void)> childProcessModifier;
286 QProcess::UnixProcessParameters processParameters;
288 std::unique_ptr<UnixExtras> unixExtras;
289 QSocketNotifier *stateNotifier =
nullptr;
290 Q_PIPE childStartedPipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
296 quint8 processState = QProcess::NotRunning;
297 quint8 exitStatus = QProcess::NormalExit;
298 quint8 processError = QProcess::UnknownError;
299 quint8 processChannelMode = QProcess::SeparateChannels;
300 quint8 inputChannelMode = QProcess::ManagedInputChannel;
301 bool emittedReadyRead =
false;
302 bool emittedBytesWritten =
false;
304 void start(QIODevice::OpenMode mode);
306#if defined(Q_OS_UNIX)
307 void commitChannels()
const;
309 bool processStarted(QString *errorMessage =
nullptr);
310 void processFinished();
311 void terminateProcess();
314 void waitForDeadChild();
319 STARTUPINFOW createStartupInfo();
320 bool callCreateProcess(QProcess::CreateProcessArguments *cpargs);
321 bool drainOutputPipes();
324 bool startDetached(qint64 *pPid);
326 bool waitForStarted(
const QDeadlineTimer &deadline);
327 bool waitForReadyRead(
const QDeadlineTimer &deadline);
328 bool waitForBytesWritten(
const QDeadlineTimer &deadline);
329 bool waitForFinished(
const QDeadlineTimer &deadline);
331 qint64 bytesAvailableInChannel(
const Channel *channel)
const;
332 qint64 readFromChannel(
const Channel *channel,
char *data, qint64 maxlen);
334 void destroyPipe(Q_PIPE pipe[2]);
336 void setError(QProcess::ProcessError error,
const QString &description = QString());
337 void setErrorAndEmit(QProcess::ProcessError error,
const QString &description = QString());
339 const QProcessEnvironmentPrivate *environmentPrivate()
const
340 {
return environment.d.constData(); }
QProcEnvValue(const QString &value)
bool operator==(const QProcEnvValue &other) const
QProcessEnvironmentPrivate(const QProcessEnvironmentPrivate &other)
Value prepareValue(const QString &value) const
QProcessEnvironmentPrivate()
static QProcessEnvironment fromList(const QStringList &list)
Key prepareName(const QString &name) const
QString valueToString(const Value &value) const
void insert(const QProcessEnvironmentPrivate &other)
QString nameToString(const Key &name) const
QStringList toList() const
QT_REQUIRE_CONFIG(animation)
bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)
QT_REQUIRE_CONFIG(processenvironment)
Q_DECLARE_TYPEINFO(QProcEnvValue, Q_RELOCATABLE_TYPE)
NameMapMutexLocker(const QProcessEnvironmentPrivate *d)
OrderedNameMapMutexLocker(const QProcessEnvironmentPrivate *d1, const QProcessEnvironmentPrivate *d2)