QProcess/Win: use named pipes for redirecting standard I/O
Named pipes allow us to make use of overlapped I/O for redirected stdin, stdout and stderr. Change-Id: I50191b036bce696147139b200ddbc6c31c16112b Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
This commit is contained in:
parent
389fc8885b
commit
9efbc9f60a
@ -48,9 +48,6 @@
|
|||||||
#include <qfileinfo.h>
|
#include <qfileinfo.h>
|
||||||
#include <qregexp.h>
|
#include <qregexp.h>
|
||||||
#include <qtimer.h>
|
#include <qtimer.h>
|
||||||
#include <qthread.h>
|
|
||||||
#include <qmutex.h>
|
|
||||||
#include <qwaitcondition.h>
|
|
||||||
#include <qwineventnotifier.h>
|
#include <qwineventnotifier.h>
|
||||||
#include <private/qthread_p.h>
|
#include <private/qthread_p.h>
|
||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
@ -66,30 +63,63 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
#define NOTIFYTIMEOUT 100
|
#define NOTIFYTIMEOUT 100
|
||||||
|
|
||||||
static void qt_create_pipe(Q_PIPE *pipe, bool in)
|
static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
|
||||||
{
|
{
|
||||||
// Open the pipes. Make non-inheritable copies of input write and output
|
// Anomymous pipes do not support asynchronous I/O. Thus we
|
||||||
// read handles to avoid non-closable handles (this is done by the
|
// create named pipes for redirecting stdout, stderr and stdin.
|
||||||
// DuplicateHandle() call).
|
|
||||||
|
|
||||||
SECURITY_ATTRIBUTES secAtt = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE };
|
SECURITY_ATTRIBUTES secAtt = { 0 };
|
||||||
|
secAtt.nLength = sizeof(secAtt);
|
||||||
|
secAtt.bInheritHandle = isInputPipe; // The read handle must be non-inheritable for output pipes.
|
||||||
|
|
||||||
HANDLE tmpHandle;
|
HANDLE hRead;
|
||||||
if (in) { // stdin
|
wchar_t pipeName[256];
|
||||||
if (!CreatePipe(&pipe[0], &tmpHandle, &secAtt, 1024 * 1024))
|
unsigned int attempts = 1000;
|
||||||
return;
|
forever {
|
||||||
if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(),
|
// ### The user must make sure to call qsrand() to make the pipe names less predictable.
|
||||||
&pipe[1], 0, FALSE, DUPLICATE_SAME_ACCESS))
|
// ### Replace the call to qrand() with a secure version, once we have it in Qt.
|
||||||
return;
|
swprintf_s(pipeName, sizeof(pipeName) / sizeof(wchar_t), L"\\\\.\\pipe\\qt-%X", qrand());
|
||||||
} else { // stdout or stderr
|
|
||||||
if (!CreatePipe(&tmpHandle, &pipe[1], &secAtt, 1024 * 1024))
|
const DWORD dwPipeBufferSize = 1024 * 1024;
|
||||||
return;
|
hRead = CreateNamedPipe(pipeName,
|
||||||
if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(),
|
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
|
||||||
&pipe[0], 0, FALSE, DUPLICATE_SAME_ACCESS))
|
PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
|
||||||
|
1, // only one pipe instance
|
||||||
|
0, // output buffer size
|
||||||
|
dwPipeBufferSize, // input buffer size
|
||||||
|
0,
|
||||||
|
&secAtt);
|
||||||
|
if (hRead != INVALID_HANDLE_VALUE)
|
||||||
|
break;
|
||||||
|
DWORD dwError = GetLastError();
|
||||||
|
if (dwError != ERROR_PIPE_BUSY || !--attempts) {
|
||||||
|
qErrnoWarning(dwError, "QProcess: CreateNamedPipe failed.", GetLastError());
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(tmpHandle);
|
// The write handle must be non-inheritable for input pipes.
|
||||||
|
secAtt.bInheritHandle = !isInputPipe;
|
||||||
|
|
||||||
|
HANDLE hWrite = INVALID_HANDLE_VALUE;
|
||||||
|
hWrite = CreateFile(pipeName,
|
||||||
|
GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
&secAtt,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_OVERLAPPED,
|
||||||
|
NULL);
|
||||||
|
if (hWrite == INVALID_HANDLE_VALUE) {
|
||||||
|
qWarning("QProcess: CreateFile failed with error code %d.\n", GetLastError());
|
||||||
|
CloseHandle(hRead);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until connection is in place.
|
||||||
|
ConnectNamedPipe(hRead, NULL);
|
||||||
|
|
||||||
|
pipe[0] = hRead;
|
||||||
|
pipe[1] = hWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void duplicateStdWriteChannel(Q_PIPE *pipe, DWORD nStdHandle)
|
static void duplicateStdWriteChannel(Q_PIPE *pipe, DWORD nStdHandle)
|
||||||
|
Loading…
Reference in New Issue
Block a user