QProcess: untangle platform-specific details

- add missing #ifdef in header file;
- split some functions (writeData(), _q_canWrite(), cleanup()) into
  their platform-specific implementations.

Change-Id: I4e7c1c377ec8468ed120d38acf2543eef9316c01
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
This commit is contained in:
Alex Trotsenko 2021-05-22 16:53:41 +03:00
parent 467b39d52c
commit f03e9164c0
4 changed files with 131 additions and 124 deletions

View File

@ -41,12 +41,8 @@
//#define QPROCESS_DEBUG
#include <qdebug.h>
#include <private/qdebug_p.h>
#include <qdir.h>
#include <qscopedvaluerollback.h>
#if defined(Q_OS_WIN)
#include <qtimer.h>
#endif
#include "qprocess.h"
#include "qprocess_p.h"
@ -54,15 +50,8 @@
#include <qbytearray.h>
#include <qdeadlinetimer.h>
#include <qcoreapplication.h>
#include <qsocketnotifier.h>
#include <qtimer.h>
#ifdef Q_OS_WIN
#include <qwineventnotifier.h>
#else
#include <private/qcore_unix_p.h>
#endif
#if __has_include(<paths.h>)
#include <paths.h>
#endif
@ -807,44 +796,6 @@ QProcessPrivate::~QProcessPrivate()
stdoutChannel.process->stdinChannel.clear();
}
/*!
\internal
*/
void QProcessPrivate::cleanup()
{
q_func()->setProcessState(QProcess::NotRunning);
#ifdef Q_OS_WIN
if (stdinWriteTrigger) {
delete stdinWriteTrigger;
stdinWriteTrigger = 0;
}
if (processFinishedNotifier) {
delete processFinishedNotifier;
processFinishedNotifier = 0;
}
if (pid) {
CloseHandle(pid->hThread);
CloseHandle(pid->hProcess);
delete pid;
pid = nullptr;
}
#else
pid = 0;
#endif
if (stateNotifier) {
delete stateNotifier;
stateNotifier = nullptr;
}
closeChannels();
destroyPipe(childStartedPipe);
#ifdef Q_OS_UNIX
if (forkfd != -1)
qt_safe_close(forkfd);
forkfd = -1;
#endif
}
/*!
\internal
*/
@ -1064,36 +1015,6 @@ bool QProcessPrivate::_q_canReadStandardError()
return tryReadFromChannel(&stderrChannel);
}
/*!
\internal
*/
bool QProcessPrivate::_q_canWrite()
{
if (writeBuffer.isEmpty()) {
#ifdef Q_OS_WIN
if (stdinChannel.closed && pipeWriterBytesToWrite() == 0)
closeWriteChannel();
#else
if (stdinChannel.notifier)
stdinChannel.notifier->setEnabled(false);
#endif
#if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::canWrite(), not writing anything (empty write buffer).");
#endif
return false;
}
const bool writeSucceeded = writeToStdin();
#ifdef Q_OS_UNIX
if (writeBuffer.isEmpty() && stdinChannel.closed)
closeWriteChannel();
else if (stdinChannel.notifier)
stdinChannel.notifier->setEnabled(!writeBuffer.isEmpty());
#endif
return writeSucceeded;
}
/*!
\internal
*/
@ -1905,44 +1826,6 @@ qint64 QProcess::readData(char *data, qint64 maxlen)
return 0;
}
/*! \reimp
*/
qint64 QProcess::writeData(const char *data, qint64 len)
{
Q_D(QProcess);
if (d->stdinChannel.closed) {
#if defined QPROCESS_DEBUG
qDebug("QProcess::writeData(%p \"%s\", %lld) == 0 (write channel closing)",
data, QtDebugUtils::toPrintable(data, len, 16).constData(), len);
#endif
return 0;
}
#if defined(Q_OS_WIN)
if (!d->stdinWriteTrigger) {
d->stdinWriteTrigger = new QTimer;
d->stdinWriteTrigger->setSingleShot(true);
QObjectPrivate::connect(d->stdinWriteTrigger, &QTimer::timeout,
d, &QProcessPrivate::_q_canWrite);
}
#endif
d->write(data, len);
#ifdef Q_OS_WIN
if (!d->stdinWriteTrigger->isActive())
d->stdinWriteTrigger->start();
#else
if (d->stdinChannel.notifier)
d->stdinChannel.notifier->setEnabled(true);
#endif
#if defined QPROCESS_DEBUG
qDebug("QProcess::writeData(%p \"%s\", %lld) == %lld (written to buffer)",
data, QtDebugUtils::toPrintable(data, len, 16).constData(), len, len);
#endif
return len;
}
/*!
Regardless of the current read channel, this function returns all
data available from the standard output of the process as a

View File

@ -330,14 +330,11 @@ public:
#endif
QProcessEnvironment environment;
#ifdef Q_OS_UNIX
Q_PIPE childStartedPipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
void destroyPipe(Q_PIPE pipe[2]);
QSocketNotifier *stateNotifier = nullptr;
int forkfd = -1;
#ifdef Q_OS_WIN
#else
QTimer *stdinWriteTrigger = nullptr;
QWinEventNotifier *processFinishedNotifier = nullptr;
#endif
@ -378,6 +375,7 @@ public:
qint64 readFromChannel(const Channel *channel, char *data, qint64 maxlen);
bool writeToStdin();
void destroyPipe(Q_PIPE pipe[2]);
void cleanup();
void setError(QProcess::ProcessError error, const QString &description = QString());
void setErrorAndEmit(QProcess::ProcessError error, const QString &description = QString());

View File

@ -276,6 +276,21 @@ void QProcessPrivate::closeChannel(Channel *channel)
destroyPipe(channel->pipe);
}
void QProcessPrivate::cleanup()
{
q_func()->setProcessState(QProcess::NotRunning);
closeChannels();
delete stateNotifier;
stateNotifier = nullptr;
destroyPipe(childStartedPipe);
pid = 0;
if (forkfd != -1) {
qt_safe_close(forkfd);
forkfd = -1;
}
}
/*
Create the pipes to a QProcessPrivate::Channel.
*/
@ -642,6 +657,52 @@ qint64 QProcessPrivate::readFromChannel(const Channel *channel, char *data, qint
return bytesRead;
}
/*! \reimp
*/
qint64 QProcess::writeData(const char *data, qint64 len)
{
Q_D(QProcess);
if (d->stdinChannel.closed) {
#if defined QPROCESS_DEBUG
qDebug("QProcess::writeData(%p \"%s\", %lld) == 0 (write channel closing)",
data, QtDebugUtils::toPrintable(data, len, 16).constData(), len);
#endif
return 0;
}
d->write(data, len);
if (d->stdinChannel.notifier)
d->stdinChannel.notifier->setEnabled(true);
#if defined QPROCESS_DEBUG
qDebug("QProcess::writeData(%p \"%s\", %lld) == %lld (written to buffer)",
data, QtDebugUtils::toPrintable(data, len, 16).constData(), len, len);
#endif
return len;
}
bool QProcessPrivate::_q_canWrite()
{
if (writeBuffer.isEmpty()) {
if (stdinChannel.notifier)
stdinChannel.notifier->setEnabled(false);
#if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::canWrite(), not writing anything (empty write buffer).");
#endif
return false;
}
const bool writeSucceeded = writeToStdin();
if (writeBuffer.isEmpty() && stdinChannel.closed)
closeWriteChannel();
else if (stdinChannel.notifier)
stdinChannel.notifier->setEnabled(!writeBuffer.isEmpty());
return writeSucceeded;
}
bool QProcessPrivate::writeToStdin()
{
const char *data = writeBuffer.readPointer();

View File

@ -39,6 +39,9 @@
****************************************************************************/
//#define QPROCESS_DEBUG
#include <qdebug.h>
#include <private/qdebug_p.h>
#include "qprocess.h"
#include "qprocess_p.h"
#include "qwindowspipereader_p.h"
@ -50,9 +53,9 @@
#include <qrandom.h>
#include <qwineventnotifier.h>
#include <qscopedvaluerollback.h>
#include <qtimer.h>
#include <private/qsystemlibrary_p.h>
#include <private/qthread_p.h>
#include <qdebug.h>
#include "private/qfsfileengine_p.h" // for longFileName
@ -375,6 +378,23 @@ void QProcessPrivate::closeChannel(Channel *channel)
destroyPipe(channel->pipe);
}
void QProcessPrivate::cleanup()
{
q_func()->setProcessState(QProcess::NotRunning);
closeChannels();
delete stdinWriteTrigger;
stdinWriteTrigger = nullptr;
delete processFinishedNotifier;
processFinishedNotifier = nullptr;
if (pid) {
CloseHandle(pid->hThread);
CloseHandle(pid->hProcess);
delete pid;
pid = nullptr;
}
}
static QString qt_create_commandline(const QString &program, const QStringList &arguments,
const QString &nativeArguments)
{
@ -816,7 +836,6 @@ bool QProcessPrivate::waitForFinished(const QDeadlineTimer &deadline)
return false;
}
void QProcessPrivate::findExitCode()
{
DWORD theExitCode;
@ -828,6 +847,38 @@ void QProcessPrivate::findExitCode()
}
}
/*! \reimp
*/
qint64 QProcess::writeData(const char *data, qint64 len)
{
Q_D(QProcess);
if (d->stdinChannel.closed) {
#if defined QPROCESS_DEBUG
qDebug("QProcess::writeData(%p \"%s\", %lld) == 0 (write channel closing)",
data, QtDebugUtils::toPrintable(data, len, 16).constData(), len);
#endif
return 0;
}
if (!d->stdinWriteTrigger) {
d->stdinWriteTrigger = new QTimer;
d->stdinWriteTrigger->setSingleShot(true);
QObjectPrivate::connect(d->stdinWriteTrigger, &QTimer::timeout,
d, &QProcessPrivate::_q_canWrite);
}
d->write(data, len);
if (!d->stdinWriteTrigger->isActive())
d->stdinWriteTrigger->start();
#if defined QPROCESS_DEBUG
qDebug("QProcess::writeData(%p \"%s\", %lld) == %lld (written to buffer)",
data, QtDebugUtils::toPrintable(data, len, 16).constData(), len, len);
#endif
return len;
}
qint64 QProcessPrivate::pipeWriterBytesToWrite() const
{
return stdinChannel.writer ? stdinChannel.writer->bytesToWrite() : qint64(0);
@ -844,6 +895,20 @@ void QProcessPrivate::_q_bytesWritten(qint64 bytes)
_q_canWrite();
}
bool QProcessPrivate::_q_canWrite()
{
if (writeBuffer.isEmpty()) {
if (stdinChannel.closed && pipeWriterBytesToWrite() == 0)
closeWriteChannel();
#if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::canWrite(), not writing anything (empty write buffer).");
#endif
return false;
}
return writeToStdin();
}
bool QProcessPrivate::writeToStdin()
{
Q_Q(QProcess);