From e650ea323f5d7146caa020b69d22ace437609883 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Sat, 12 Jun 2021 15:35:28 +0300 Subject: [PATCH] QWindowsPipeWriter: centralize write result handling Both code paths (write() for the main thread and waitCallback() for the worker thread) use the same logic when processing write results. To avoid code duplication, consolidate the common part for both threads in the startAsyncWriteLocked() function. Change-Id: Ie2663b2ed221e2797a1ecbdb3fcee0ee8f030cc0 Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qwindowspipewriter.cpp | 62 ++++++++++++--------------- src/corelib/io/qwindowspipewriter_p.h | 3 +- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp index cfa486451c9..83282032e21 100644 --- a/src/corelib/io/qwindowspipewriter.cpp +++ b/src/corelib/io/qwindowspipewriter.cpp @@ -145,37 +145,19 @@ inline bool QWindowsPipeWriter::writeImpl(Args... args) return false; writeBuffer.append(args...); - return writeImplTail(&locker); -} -bool QWindowsPipeWriter::writeImplTail(QMutexLocker *locker) -{ if (writeSequenceStarted) return true; stopped = false; - startAsyncWriteLocked(); - - // Do not post the event, if the write operation will be completed asynchronously. - if (!bytesWrittenPending) - return true; - - if (!winEventActPosted) { - winEventActPosted = true; - locker->unlock(); - QCoreApplication::postEvent(this, new QEvent(QEvent::WinEventAct)); - } else { - locker->unlock(); - } - - SetEvent(syncHandle); + startAsyncWriteLocked(&locker); return true; } /*! - Starts a new write sequence. Thread-safety should be ensured by the caller. + Starts a new write sequence. */ -void QWindowsPipeWriter::startAsyncWriteLocked() +void QWindowsPipeWriter::startAsyncWriteLocked(QMutexLocker *locker) { while (!writeBuffer.isEmpty()) { // WriteFile() returns true, if the write operation completes synchronously. @@ -190,13 +172,29 @@ void QWindowsPipeWriter::startAsyncWriteLocked() // Operation has been queued and will complete in the future. writeSequenceStarted = true; SetThreadpoolWait(waitObject, eventHandle, NULL); - return; + break; } } if (!writeCompleted(errorCode, numberOfBytesWritten)) - return; + break; } + + // Do not post the event, if the write operation will be completed asynchronously. + if (!bytesWrittenPending) + return; + + if (!winEventActPosted) { + winEventActPosted = true; + locker->unlock(); + QCoreApplication::postEvent(this, new QEvent(QEvent::WinEventAct)); + } else { + locker->unlock(); + } + + // We set the event only after unlocking to avoid additional context + // switches due to the released thread immediately running into the lock. + SetEvent(syncHandle); } /*! @@ -228,20 +226,16 @@ void QWindowsPipeWriter::waitCallback(PTP_CALLBACK_INSTANCE instance, PVOID cont pipeWriter->writeSequenceStarted = false; - if (pipeWriter->writeCompleted(errorCode, numberOfBytesTransfered)) - pipeWriter->startAsyncWriteLocked(); - - if (pipeWriter->lastError == ERROR_SUCCESS && !pipeWriter->winEventActPosted) { - pipeWriter->winEventActPosted = true; - locker.unlock(); - QCoreApplication::postEvent(pipeWriter, new QEvent(QEvent::WinEventAct)); + if (pipeWriter->writeCompleted(errorCode, numberOfBytesTransfered)) { + pipeWriter->startAsyncWriteLocked(&locker); } else { + // The write operation failed, so we must unblock the main thread, + // which can wait for the event. We set the event only after unlocking + // to avoid additional context switches due to the released thread + // immediately running into the lock. locker.unlock(); + SetEvent(pipeWriter->syncHandle); } - - // We set the event only after unlocking to avoid additional context - // switches due to the released thread immediately running into the lock. - SetEvent(pipeWriter->syncHandle); } /*! diff --git a/src/corelib/io/qwindowspipewriter_p.h b/src/corelib/io/qwindowspipewriter_p.h index f8cabb225da..11d1abba59f 100644 --- a/src/corelib/io/qwindowspipewriter_p.h +++ b/src/corelib/io/qwindowspipewriter_p.h @@ -86,9 +86,8 @@ protected: private: template inline bool writeImpl(Args... args); - bool writeImplTail(QMutexLocker *locker); - void startAsyncWriteLocked(); + void startAsyncWriteLocked(QMutexLocker *locker); static void CALLBACK waitCallback(PTP_CALLBACK_INSTANCE instance, PVOID context, PTP_WAIT wait, TP_WAIT_RESULT waitResult); bool writeCompleted(DWORD errorCode, DWORD numberOfBytesWritten);