diff options
| -rw-r--r-- | src/corelib/io/qprocess.cpp | 8 | ||||
| -rw-r--r-- | src/corelib/io/qprocess.h | 2 | ||||
| -rw-r--r-- | src/corelib/io/qprocess_p.h | 9 | ||||
| -rw-r--r-- | src/corelib/io/qprocess_win.cpp | 74 | ||||
| -rw-r--r-- | src/corelib/io/qwindowspipewriter.cpp | 19 | ||||
| -rw-r--r-- | src/corelib/io/qwindowspipewriter_p.h | 1 |
6 files changed, 52 insertions, 61 deletions
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 0702667042d..0f2de9e1ff7 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -782,7 +782,9 @@ void QProcessPrivate::Channel::clear() QProcessPrivate::QProcessPrivate() { readBufferChunkSize = QRINGBUFFER_CHUNKSIZE; +#ifndef Q_OS_WIN writeBufferChunkSize = QRINGBUFFER_CHUNKSIZE; +#endif } /*! @@ -1585,11 +1587,11 @@ bool QProcess::isSequential() const */ qint64 QProcess::bytesToWrite() const { - qint64 size = QIODevice::bytesToWrite(); #ifdef Q_OS_WIN - size += d_func()->pipeWriterBytesToWrite(); + return d_func()->pipeWriterBytesToWrite(); +#else + return QIODevice::bytesToWrite(); #endif - return size; } /*! diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index f9c05a4f292..e1b8cc7f57f 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -281,7 +281,9 @@ private: Q_PRIVATE_SLOT(d_func(), bool _q_canReadStandardOutput()) Q_PRIVATE_SLOT(d_func(), bool _q_canReadStandardError()) +#ifdef Q_OS_UNIX Q_PRIVATE_SLOT(d_func(), bool _q_canWrite()) +#endif Q_PRIVATE_SLOT(d_func(), bool _q_startupNotification()) Q_PRIVATE_SLOT(d_func(), void _q_processDied()) }; diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 078c617021c..74ab6ab4097 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -81,7 +81,6 @@ class QSocketNotifier; class QWindowsPipeReader; class QWindowsPipeWriter; class QWinEventNotifier; -class QTimer; #ifdef Q_OS_WIN class QProcEnvKey : public QString @@ -286,9 +285,12 @@ public: bool _q_canReadStandardOutput(); bool _q_canReadStandardError(); #ifdef Q_OS_WIN + qint64 pipeWriterBytesToWrite() const; void _q_bytesWritten(qint64 bytes); -#endif +#else bool _q_canWrite(); + bool writeToStdin(); +#endif bool _q_startupNotification(); void _q_processDied(); @@ -335,7 +337,6 @@ public: QSocketNotifier *stateNotifier = nullptr; int forkfd = -1; #else - QTimer *stdinWriteTrigger = nullptr; QWinEventNotifier *processFinishedNotifier = nullptr; #endif @@ -357,7 +358,6 @@ public: STARTUPINFOW createStartupInfo(); bool callCreateProcess(QProcess::CreateProcessArguments *cpargs); bool drainOutputPipes(); - qint64 pipeWriterBytesToWrite() const; #endif bool startDetached(qint64 *pPid); @@ -373,7 +373,6 @@ public: qint64 bytesAvailableInChannel(const Channel *channel) const; qint64 readFromChannel(const Channel *channel, char *data, qint64 maxlen); - bool writeToStdin(); void destroyPipe(Q_PIPE pipe[2]); void cleanup(); diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index e557d104534..24031b9163a 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -53,7 +53,6 @@ #include <qrandom.h> #include <qwineventnotifier.h> #include <qscopedvaluerollback.h> -#include <qtimer.h> #include <private/qsystemlibrary_p.h> #include <private/qthread_p.h> @@ -376,8 +375,6 @@ void QProcessPrivate::cleanup() q_func()->setProcessState(QProcess::NotRunning); closeChannels(); - delete stdinWriteTrigger; - stdinWriteTrigger = nullptr; delete processFinishedNotifier; processFinishedNotifier = nullptr; if (pid) { @@ -618,6 +615,12 @@ void QProcessPrivate::startProcess() return; } + // The pipe writer may have already been created before we had + // the pipe handle, specifically if the user wrote data from the + // stateChanged() slot. + if (stdinChannel.writer) + stdinChannel.writer->setHandle(stdinChannel.pipe[1]); + q->setProcessState(QProcess::Running); // User can call kill()/terminate() from the stateChanged() slot // so check before proceeding @@ -713,9 +716,6 @@ bool QProcessPrivate::drainOutputPipes() bool QProcessPrivate::waitForReadyRead(const QDeadlineTimer &deadline) { forever { - if (!writeBuffer.isEmpty() && !_q_canWrite()) - return false; - QProcessPoller poller(*this); int ret = poller.poll(deadline); if (ret < 0) @@ -748,10 +748,11 @@ bool QProcessPrivate::waitForReadyRead(const QDeadlineTimer &deadline) bool QProcessPrivate::waitForBytesWritten(const QDeadlineTimer &deadline) { forever { - // If no write is pending, try to start one. However, at entry into - // the loop the write buffer can be empty to start with, in which - // case _q_caWrite() fails immediately. - if (pipeWriterBytesToWrite() == 0 && !_q_canWrite()) + // At entry into the loop the pipe writer's buffer can be empty to + // start with, in which case we fail immediately. Also, if the input + // pipe goes down somewhere in the code below, we avoid waiting for + // a full timeout. + if (pipeWriterBytesToWrite() == 0) return false; QProcessPoller poller(*this); @@ -797,9 +798,6 @@ bool QProcessPrivate::waitForFinished(const QDeadlineTimer &deadline) #endif forever { - if (!writeBuffer.isEmpty() && !_q_canWrite()) - return false; - QProcessPoller poller(*this); int ret = poller.poll(deadline); if (ret < 0) @@ -854,16 +852,16 @@ qint64 QProcess::writeData(const char *data, qint64 len) return 0; } - if (!d->stdinWriteTrigger) { - d->stdinWriteTrigger = new QTimer; - d->stdinWriteTrigger->setSingleShot(true); - QObjectPrivate::connect(d->stdinWriteTrigger, &QTimer::timeout, - d, &QProcessPrivate::_q_canWrite); + if (!d->stdinChannel.writer) { + d->stdinChannel.writer = new QWindowsPipeWriter(d->stdinChannel.pipe[1], this); + QObjectPrivate::connect(d->stdinChannel.writer, &QWindowsPipeWriter::bytesWritten, + d, &QProcessPrivate::_q_bytesWritten); } - d->write(data, len); - if (!d->stdinWriteTrigger->isActive()) - d->stdinWriteTrigger->start(); + if (d->isWriteChunkCached(data, len)) + d->stdinChannel.writer->write(*(d->currentWriteChunk)); + else + d->stdinChannel.writer->write(data, len); #if defined QPROCESS_DEBUG qDebug("QProcess::writeData(%p \"%s\", %lld) == %lld (written to buffer)", @@ -885,38 +883,8 @@ void QProcessPrivate::_q_bytesWritten(qint64 bytes) QScopedValueRollback<bool> guard(emittedBytesWritten, true); emit q->bytesWritten(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); - - if (!stdinChannel.writer) { - stdinChannel.writer = new QWindowsPipeWriter(stdinChannel.pipe[1], q); - QObjectPrivate::connect(stdinChannel.writer, &QWindowsPipeWriter::bytesWritten, - this, &QProcessPrivate::_q_bytesWritten); - } else { - if (stdinChannel.writer->isWriteOperationActive()) - return true; - } - - stdinChannel.writer->write(writeBuffer.read()); - return true; + if (stdinChannel.closed && pipeWriterBytesToWrite() == 0) + closeWriteChannel(); } // Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp index 83282032e21..6a5e43db0df 100644 --- a/src/corelib/io/qwindowspipewriter.cpp +++ b/src/corelib/io/qwindowspipewriter.cpp @@ -73,6 +73,19 @@ QWindowsPipeWriter::~QWindowsPipeWriter() } /*! + Assigns the handle to this writer. The handle must be valid. + Call this function if data was buffered before getting the handle. + */ +void QWindowsPipeWriter::setHandle(HANDLE hPipeWriteEnd) +{ + Q_ASSERT(!stopped); + + handle = hPipeWriteEnd; + QMutexLocker locker(&mutex); + startAsyncWriteLocked(&locker); +} + +/*! Stops the asynchronous write sequence. If the write sequence is running then the I/O operation is canceled. */ @@ -150,6 +163,12 @@ inline bool QWindowsPipeWriter::writeImpl(Args... args) return true; stopped = false; + + // If we don't have an assigned handle yet, defer writing until + // setHandle() is called. + if (handle == INVALID_HANDLE_VALUE) + return true; + startAsyncWriteLocked(&locker); return true; } diff --git a/src/corelib/io/qwindowspipewriter_p.h b/src/corelib/io/qwindowspipewriter_p.h index 11d1abba59f..e20f1ec90a5 100644 --- a/src/corelib/io/qwindowspipewriter_p.h +++ b/src/corelib/io/qwindowspipewriter_p.h @@ -68,6 +68,7 @@ public: explicit QWindowsPipeWriter(HANDLE pipeWriteEnd, QObject *parent = nullptr); ~QWindowsPipeWriter(); + void setHandle(HANDLE hPipeWriteEnd); bool write(const QByteArray &ba); bool write(const char *data, qint64 size); void stop(); |
