QProcess: allow merged channels forwarding for detached processes
[ChangeLog][QtCore][QProcess] Added support for QProcess::MergedChannels mode with startDetached(). Change-Id: I953ad2063322015332269522a297f8e2842e438c Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
This commit is contained in:
parent
1fb9c5348e
commit
04c34eb799
@ -616,7 +616,8 @@ void QProcessPrivate::Channel::clear()
|
|||||||
process into the standard output channel (\c stdout). The
|
process into the standard output channel (\c stdout). The
|
||||||
standard error channel (\c stderr) will not receive any data. The
|
standard error channel (\c stderr) will not receive any data. The
|
||||||
standard output and standard error data of the running process
|
standard output and standard error data of the running process
|
||||||
are interleaved.
|
are interleaved. For detached processes, the merged output of the
|
||||||
|
running process is forwarded onto the main process.
|
||||||
|
|
||||||
\value ForwardedChannels QProcess forwards the output of the
|
\value ForwardedChannels QProcess forwards the output of the
|
||||||
running process onto the main process. Anything the child process
|
running process onto the main process. Anything the child process
|
||||||
@ -1000,10 +1001,11 @@ bool QProcessPrivate::openChannelsForDetached()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// stderr channel.
|
// stderr channel.
|
||||||
if (processChannelMode == QProcess::MergedChannels || (stderrChannel.type != Channel::Normal
|
if (stderrChannel.type != Channel::Normal
|
||||||
&& (stderrChannel.type != Channel::Redirect
|
&& (stderrChannel.type != Channel::Redirect
|
||||||
|| processChannelMode == QProcess::ForwardedChannels
|
|| processChannelMode == QProcess::ForwardedChannels
|
||||||
|| processChannelMode == QProcess::ForwardedErrorChannel))) {
|
|| processChannelMode == QProcess::ForwardedErrorChannel
|
||||||
|
|| processChannelMode == QProcess::MergedChannels)) {
|
||||||
qWarning("QProcess::openChannelsForDetached: Inconsistent stderr channel configuration");
|
qWarning("QProcess::openChannelsForDetached: Inconsistent stderr channel configuration");
|
||||||
}
|
}
|
||||||
if (stderrChannel.type == Channel::Redirect && !openChannel(stderrChannel))
|
if (stderrChannel.type == Channel::Redirect && !openChannel(stderrChannel))
|
||||||
@ -2172,6 +2174,7 @@ void QProcess::startCommand(const QString &command, OpenMode mode)
|
|||||||
\li setStandardErrorFile()
|
\li setStandardErrorFile()
|
||||||
\li setStandardInputFile()
|
\li setStandardInputFile()
|
||||||
\li setStandardOutputFile()
|
\li setStandardOutputFile()
|
||||||
|
\li setProcessChannelMode(QProcess::MergedChannels)
|
||||||
\li setWorkingDirectory()
|
\li setWorkingDirectory()
|
||||||
\endlist
|
\endlist
|
||||||
All other properties of the QProcess object are ignored.
|
All other properties of the QProcess object are ignored.
|
||||||
|
@ -319,6 +319,9 @@ public:
|
|||||||
bool openChannels();
|
bool openChannels();
|
||||||
bool openChannelsForDetached();
|
bool openChannelsForDetached();
|
||||||
bool openChannel(Channel &channel);
|
bool openChannel(Channel &channel);
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
void commitChannels();
|
||||||
|
#endif
|
||||||
void closeChannel(Channel *channel);
|
void closeChannel(Channel *channel);
|
||||||
void closeWriteChannel();
|
void closeWriteChannel();
|
||||||
bool tryReadFromChannel(Channel *channel); // obviously, only stdout and stderr
|
bool tryReadFromChannel(Channel *channel); // obviously, only stdout and stderr
|
||||||
|
@ -319,6 +319,24 @@ bool QProcessPrivate::openChannel(Channel &channel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QProcessPrivate::commitChannels()
|
||||||
|
{
|
||||||
|
// copy the stdin socket if asked to (without closing on exec)
|
||||||
|
if (stdinChannel.pipe[0] != INVALID_Q_PIPE)
|
||||||
|
qt_safe_dup2(stdinChannel.pipe[0], STDIN_FILENO, 0);
|
||||||
|
|
||||||
|
// copy the stdout and stderr if asked to
|
||||||
|
if (stdoutChannel.pipe[1] != INVALID_Q_PIPE)
|
||||||
|
qt_safe_dup2(stdoutChannel.pipe[1], STDOUT_FILENO, 0);
|
||||||
|
if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
|
||||||
|
qt_safe_dup2(stderrChannel.pipe[1], STDERR_FILENO, 0);
|
||||||
|
} else {
|
||||||
|
// merge stdout and stderr if asked to
|
||||||
|
if (processChannelMode == QProcess::MergedChannels)
|
||||||
|
qt_safe_dup2(STDOUT_FILENO, STDERR_FILENO, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Map &environment, int *envc)
|
static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Map &environment, int *envc)
|
||||||
{
|
{
|
||||||
*envc = 0;
|
*envc = 0;
|
||||||
@ -525,20 +543,8 @@ void QProcessPrivate::execChild(const char *workingDir, char **argv, char **envp
|
|||||||
|
|
||||||
ChildError error = { 0, {} }; // force zeroing of function[8]
|
ChildError error = { 0, {} }; // force zeroing of function[8]
|
||||||
|
|
||||||
// copy the stdin socket if asked to (without closing on exec)
|
// Render channels configuration.
|
||||||
if (stdinChannel.pipe[0] != INVALID_Q_PIPE)
|
commitChannels();
|
||||||
qt_safe_dup2(stdinChannel.pipe[0], STDIN_FILENO, 0);
|
|
||||||
|
|
||||||
// copy the stdout and stderr if asked to
|
|
||||||
if (stdoutChannel.pipe[1] != INVALID_Q_PIPE)
|
|
||||||
qt_safe_dup2(stdoutChannel.pipe[1], STDOUT_FILENO, 0);
|
|
||||||
if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
|
|
||||||
qt_safe_dup2(stderrChannel.pipe[1], STDERR_FILENO, 0);
|
|
||||||
} else {
|
|
||||||
// merge stdout and stderr if asked to
|
|
||||||
if (processChannelMode == QProcess::MergedChannels)
|
|
||||||
qt_safe_dup2(STDOUT_FILENO, STDERR_FILENO, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure this fd is closed if execv() succeeds
|
// make sure this fd is closed if execv() succeeds
|
||||||
qt_safe_close(childStartedPipe[0]);
|
qt_safe_close(childStartedPipe[0]);
|
||||||
@ -901,15 +907,8 @@ bool QProcessPrivate::startDetached(qint64 *pid)
|
|||||||
if (doubleForkPid == 0) {
|
if (doubleForkPid == 0) {
|
||||||
qt_safe_close(pidPipe[1]);
|
qt_safe_close(pidPipe[1]);
|
||||||
|
|
||||||
// copy the stdin socket if asked to (without closing on exec)
|
// Render channels configuration.
|
||||||
if (stdinChannel.type == Channel::Redirect)
|
commitChannels();
|
||||||
qt_safe_dup2(stdinChannel.pipe[0], STDIN_FILENO, 0);
|
|
||||||
|
|
||||||
// copy the stdout and stderr if asked to
|
|
||||||
if (stdoutChannel.type == Channel::Redirect)
|
|
||||||
qt_safe_dup2(stdoutChannel.pipe[1], STDOUT_FILENO, 0);
|
|
||||||
if (stderrChannel.type == Channel::Redirect)
|
|
||||||
qt_safe_dup2(stderrChannel.pipe[1], STDERR_FILENO, 0);
|
|
||||||
|
|
||||||
if (!encodedWorkingDirectory.isEmpty()) {
|
if (!encodedWorkingDirectory.isEmpty()) {
|
||||||
if (QT_CHDIR(encodedWorkingDirectory.constData()) == -1)
|
if (QT_CHDIR(encodedWorkingDirectory.constData()) == -1)
|
||||||
|
@ -914,17 +914,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
|
|||||||
|
|
||||||
DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
|
DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
|
||||||
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
|
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
|
||||||
STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
|
STARTUPINFOW startupInfo = createStartupInfo();
|
||||||
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
|
|
||||||
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
|
|
||||||
0, 0, 0,
|
|
||||||
STARTF_USESTDHANDLES,
|
|
||||||
0, 0, 0,
|
|
||||||
pipeOrStdHandle(stdinChannel.pipe[0], STD_INPUT_HANDLE),
|
|
||||||
pipeOrStdHandle(stdoutChannel.pipe[1], STD_OUTPUT_HANDLE),
|
|
||||||
pipeOrStdHandle(stderrChannel.pipe[1], STD_ERROR_HANDLE)
|
|
||||||
};
|
|
||||||
|
|
||||||
QProcess::CreateProcessArguments cpargs = {
|
QProcess::CreateProcessArguments cpargs = {
|
||||||
nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())),
|
nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())),
|
||||||
nullptr, nullptr, true, dwCreationFlags, envPtr,
|
nullptr, nullptr, true, dwCreationFlags, envPtr,
|
||||||
|
@ -36,8 +36,8 @@ int main(int argc, char *argv[])
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fputs("out data", stdout);
|
fputs("out data", stdout);
|
||||||
fputs("err data", stderr);
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
fputs("err data", stderr);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
std::ofstream out(argv[1]);
|
std::ofstream out(argv[1]);
|
||||||
out << "That's all folks!";
|
out << "That's all folks!";
|
||||||
|
@ -1125,6 +1125,10 @@ void tst_QProcess::forwardedChannels_data()
|
|||||||
<< true
|
<< true
|
||||||
<< int(QProcess::SeparateChannels) << int(QProcess::ManagedInputChannel)
|
<< int(QProcess::SeparateChannels) << int(QProcess::ManagedInputChannel)
|
||||||
<< QByteArray("out data") << QByteArray("err data");
|
<< QByteArray("out data") << QByteArray("err data");
|
||||||
|
QTest::newRow("detached-merged-forwarding")
|
||||||
|
<< true
|
||||||
|
<< int(QProcess::MergedChannels) << int(QProcess::ManagedInputChannel)
|
||||||
|
<< QByteArray("out data" "err data") << QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QProcess::forwardedChannels()
|
void tst_QProcess::forwardedChannels()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user