From d4fd9963634b581795a49a821394d89d8115d480 Mon Sep 17 00:00:00 2001 From: Andreas Buhr Date: Thu, 25 Mar 2021 09:14:53 +0100 Subject: [PATCH 1/2] Adapt Catch2 to Apple Silicon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are still using Catch2 2.11.3 which is not adapted to Apple silicon yet. This patch backports the required change from Catch v3.0.0-preview.3. Change-Id: Ifa14a1fdd6cd1f661c94a0a78648cb01bd9699c1 Reviewed-by: Tor Arne Vestbø --- tests/auto/testlib/selftests/catch_p_p.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/auto/testlib/selftests/catch_p_p.h b/tests/auto/testlib/selftests/catch_p_p.h index 97ce7a24fd3..596bfe63dd9 100644 --- a/tests/auto/testlib/selftests/catch_p_p.h +++ b/tests/auto/testlib/selftests/catch_p_p.h @@ -7872,7 +7872,13 @@ namespace Catch { #ifdef CATCH_PLATFORM_MAC - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + // taken from Catch v3.0.0-preview.3 + #if defined(__i386__) || defined(__x86_64__) + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + #elif defined(__aarch64__) + #define CATCH_TRAP() __asm__(".inst 0xd4200000") + #endif + // end taken from Catch v3.0.0-preview.3 #elif defined(CATCH_PLATFORM_IPHONE) From 82c67623db5d9708d2565bed2e8f68ad3dd190b1 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Fri, 19 Mar 2021 18:29:50 +0200 Subject: [PATCH 2/2] QProcess/Win: get rid of incremental wait Introduce QProcessPoller helper class on Windows that implements waiting for any activity from a child process. Change-Id: I99414db4424b4342e0fa3d7a3789f85cad76d190 Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qprocess_win.cpp | 112 ++++++++++++++++++-------- src/corelib/io/qwindowspipereader.cpp | 3 +- src/corelib/io/qwindowspipereader_p.h | 2 + src/corelib/io/qwindowspipewriter.cpp | 3 +- src/corelib/io/qwindowspipewriter_p.h | 52 +----------- 5 files changed, 87 insertions(+), 85 deletions(-) diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 84fbeb539d5..7c261e75586 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -85,6 +85,46 @@ QProcessEnvironment QProcessEnvironment::systemEnvironment() #if QT_CONFIG(process) +namespace { +struct QProcessPoller +{ + QProcessPoller(const QProcessPrivate &proc); + + int poll(const QDeadlineTimer &deadline); + + enum { maxHandles = 4 }; + HANDLE handles[maxHandles]; + DWORD handleCount = 0; +}; + +QProcessPoller::QProcessPoller(const QProcessPrivate &proc) +{ + if (proc.stdinChannel.writer) + handles[handleCount++] = proc.stdinChannel.writer->syncEvent(); + if (proc.stdoutChannel.reader) + handles[handleCount++] = proc.stdoutChannel.reader->syncEvent(); + if (proc.stderrChannel.reader) + handles[handleCount++] = proc.stderrChannel.reader->syncEvent(); + + handles[handleCount++] = proc.pid->hProcess; +} + +int QProcessPoller::poll(const QDeadlineTimer &deadline) +{ + DWORD waitRet; + + do { + waitRet = WaitForMultipleObjectsEx(handleCount, handles, FALSE, + deadline.remainingTime(), TRUE); + } while (waitRet == WAIT_IO_COMPLETION); + + if (waitRet - WAIT_OBJECT_0 < handleCount) + return 1; + + return (waitRet == WAIT_TIMEOUT) ? 0 : -1; +} +} // anonymous namespace + static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag) { // Anomymous pipes do not support asynchronous I/O. Thus we @@ -658,16 +698,22 @@ bool QProcessPrivate::drainOutputPipes() bool QProcessPrivate::waitForReadyRead(const QDeadlineTimer &deadline) { - QIncrementalSleepTimer timer(deadline.remainingTime()); - forever { if (!writeBuffer.isEmpty() && !_q_canWrite()) return false; - if (stdinChannel.writer && stdinChannel.writer->waitForWrite(0)) - timer.resetIncrements(); - if ((stdoutChannel.reader && stdoutChannel.reader->waitForReadyRead(0)) - || (stderrChannel.reader && stderrChannel.reader->waitForReadyRead(0))) + QProcessPoller poller(*this); + int ret = poller.poll(deadline); + if (ret < 0) + return false; + if (ret == 0) + break; + + if (stdinChannel.writer) + stdinChannel.writer->checkForWrite(); + + if ((stdoutChannel.reader && stdoutChannel.reader->checkForReadyRead()) + || (stderrChannel.reader && stderrChannel.reader->checkForReadyRead())) return true; if (!pid) @@ -678,10 +724,6 @@ bool QProcessPrivate::waitForReadyRead(const QDeadlineTimer &deadline) processFinished(); return readyReadEmitted; } - - Sleep(timer.nextSleepTime()); - if (timer.hasTimedOut()) - break; } setError(QProcess::Timedout); @@ -690,8 +732,6 @@ bool QProcessPrivate::waitForReadyRead(const QDeadlineTimer &deadline) bool QProcessPrivate::waitForBytesWritten(const QDeadlineTimer &deadline) { - QIncrementalSleepTimer timer(deadline.remainingTime()); - 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 @@ -699,17 +739,24 @@ bool QProcessPrivate::waitForBytesWritten(const QDeadlineTimer &deadline) if (pipeWriterBytesToWrite() == 0 && !_q_canWrite()) return false; + QProcessPoller poller(*this); + int ret = poller.poll(deadline); + if (ret < 0) + return false; + if (ret == 0) + break; + Q_ASSERT(stdinChannel.writer); - if (stdinChannel.writer->waitForWrite(0)) + if (stdinChannel.writer->checkForWrite()) return true; // If we wouldn't write anything, check if we can read stdout. - if (stdoutChannel.reader && stdoutChannel.reader->waitForReadyRead(0)) - timer.resetIncrements(); + if (stdoutChannel.reader) + stdoutChannel.reader->checkForReadyRead(); // Check if we can read stderr. - if (stderrChannel.reader && stderrChannel.reader->waitForReadyRead(0)) - timer.resetIncrements(); + if (stderrChannel.reader) + stderrChannel.reader->checkForReadyRead(); // Check if the process died while reading. if (!pid) @@ -723,10 +770,6 @@ bool QProcessPrivate::waitForBytesWritten(const QDeadlineTimer &deadline) processFinished(); return false; } - - // Only wait for as long as we've been asked. - if (timer.hasTimedOut()) - break; } setError(QProcess::Timedout); @@ -739,30 +782,33 @@ bool QProcessPrivate::waitForFinished(const QDeadlineTimer &deadline) qDebug("QProcessPrivate::waitForFinished(%lld)", deadline.remainingTime()); #endif - QIncrementalSleepTimer timer(deadline.remainingTime()); - forever { if (!writeBuffer.isEmpty() && !_q_canWrite()) return false; - if (stdinChannel.writer && stdinChannel.writer->waitForWrite(0)) - timer.resetIncrements(); - if (stdoutChannel.reader && stdoutChannel.reader->waitForReadyRead(0)) - timer.resetIncrements(); - if (stderrChannel.reader && stderrChannel.reader->waitForReadyRead(0)) - timer.resetIncrements(); + + QProcessPoller poller(*this); + int ret = poller.poll(deadline); + if (ret < 0) + return false; + if (ret == 0) + break; + + if (stdinChannel.writer) + stdinChannel.writer->checkForWrite(); + if (stdoutChannel.reader) + stdoutChannel.reader->checkForReadyRead(); + if (stderrChannel.reader) + stderrChannel.reader->checkForReadyRead(); if (!pid) return true; - if (WaitForSingleObject(pid->hProcess, timer.nextSleepTime()) == WAIT_OBJECT_0) { + if (WaitForSingleObject(pid->hProcess, 0) == WAIT_OBJECT_0) { drainOutputPipes(); if (pid) processFinished(); return true; } - - if (timer.hasTimedOut()) - break; } setError(QProcess::Timedout); diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index bf03737c393..638405ae75f 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -51,7 +51,7 @@ QWindowsPipeReader::QWindowsPipeReader(QObject *parent) : QObject(parent), handle(INVALID_HANDLE_VALUE), eventHandle(CreateEvent(NULL, FALSE, FALSE, NULL)), - syncHandle(CreateEvent(NULL, FALSE, FALSE, NULL)), + syncHandle(CreateEvent(NULL, TRUE, FALSE, NULL)), waitObject(NULL), readBufferMaxSize(0), actualReadBufferSize(0), @@ -396,6 +396,7 @@ bool QWindowsPipeReader::event(QEvent *e) */ bool QWindowsPipeReader::consumePendingAndEmit(bool allowWinActPosting) { + ResetEvent(syncHandle); mutex.lock(); // Enable QEvent::WinEventAct posting. diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h index a284f55b3b6..8ae292da46f 100644 --- a/src/corelib/io/qwindowspipereader_p.h +++ b/src/corelib/io/qwindowspipereader_p.h @@ -81,9 +81,11 @@ public: qint64 read(char *data, qint64 maxlen); bool canReadLine() const; bool waitForReadyRead(int msecs); + bool checkForReadyRead() { return consumePendingAndEmit(false); } bool waitForPipeClosed(int msecs); bool isReadOperationActive() const; + HANDLE syncEvent() const { return syncHandle; } Q_SIGNALS: void winError(ulong, const QString &); diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp index 5ed584c6e31..d711528c8f0 100644 --- a/src/corelib/io/qwindowspipewriter.cpp +++ b/src/corelib/io/qwindowspipewriter.cpp @@ -49,7 +49,7 @@ QWindowsPipeWriter::QWindowsPipeWriter(HANDLE pipeWriteEnd, QObject *parent) : QObject(parent), handle(pipeWriteEnd), eventHandle(CreateEvent(NULL, FALSE, FALSE, NULL)), - syncHandle(CreateEvent(NULL, FALSE, FALSE, NULL)), + syncHandle(CreateEvent(NULL, TRUE, FALSE, NULL)), waitObject(NULL), pendingBytesWrittenValue(0), lastError(ERROR_SUCCESS), @@ -267,6 +267,7 @@ bool QWindowsPipeWriter::event(QEvent *e) */ bool QWindowsPipeWriter::consumePendingAndEmit(bool allowWinActPosting) { + ResetEvent(syncHandle); QMutexLocker locker(&mutex); // Enable QEvent::WinEventAct posting. diff --git a/src/corelib/io/qwindowspipewriter_p.h b/src/corelib/io/qwindowspipewriter_p.h index b648d7b8463..d33c2753a82 100644 --- a/src/corelib/io/qwindowspipewriter_p.h +++ b/src/corelib/io/qwindowspipewriter_p.h @@ -52,8 +52,6 @@ // We mean it. // -#include -#include #include #include #include @@ -63,54 +61,6 @@ QT_BEGIN_NAMESPACE -#define SLEEPMIN 10 -#define SLEEPMAX 500 - -class QIncrementalSleepTimer -{ - -public: - QIncrementalSleepTimer(int msecs) - : totalTimeOut(msecs) - , nextSleep(qMin(SLEEPMIN, totalTimeOut)) - { - if (totalTimeOut == -1) - nextSleep = SLEEPMIN; - timer.start(); - } - - int nextSleepTime() - { - int tmp = nextSleep; - nextSleep = qMin(nextSleep * 2, qMin(SLEEPMAX, timeLeft())); - return tmp; - } - - int timeLeft() const - { - if (totalTimeOut == -1) - return SLEEPMAX; - return qMax(int(totalTimeOut - timer.elapsed()), 0); - } - - bool hasTimedOut() const - { - if (totalTimeOut == -1) - return false; - return timer.elapsed() >= totalTimeOut; - } - - void resetIncrements() - { - nextSleep = qMin(SLEEPMIN, timeLeft()); - } - -private: - QElapsedTimer timer; - int totalTimeOut; - int nextSleep; -}; - class Q_CORE_EXPORT QWindowsPipeWriter : public QObject { Q_OBJECT @@ -121,8 +71,10 @@ public: bool write(const QByteArray &ba); void stop(); bool waitForWrite(int msecs); + bool checkForWrite() { return consumePendingAndEmit(false); } bool isWriteOperationActive() const; qint64 bytesToWrite() const; + HANDLE syncEvent() const { return syncHandle; } Q_SIGNALS: void canWrite();