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 <oswald.buddenhagen@gmx.de>
This commit is contained in:
Alex Trotsenko 2021-06-12 15:35:28 +03:00
parent 329683795d
commit e650ea323f
2 changed files with 29 additions and 36 deletions

View File

@ -145,37 +145,19 @@ inline bool QWindowsPipeWriter::writeImpl(Args... args)
return false;
writeBuffer.append(args...);
return writeImplTail(&locker);
}
bool QWindowsPipeWriter::writeImplTail(QMutexLocker<QMutex> *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<QMutex> *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);
}
/*!

View File

@ -86,9 +86,8 @@ protected:
private:
template <typename... Args>
inline bool writeImpl(Args... args);
bool writeImplTail(QMutexLocker<QMutex> *locker);
void startAsyncWriteLocked();
void startAsyncWriteLocked(QMutexLocker<QMutex> *locker);
static void CALLBACK waitCallback(PTP_CALLBACK_INSTANCE instance, PVOID context,
PTP_WAIT wait, TP_WAIT_RESULT waitResult);
bool writeCompleted(DWORD errorCode, DWORD numberOfBytesWritten);