QLocalSocket/Win: avoid double buffering on write
As QWindowsPipeWriter now maintains a chunk queue, there is no need to use the internal QIODevice buffer and wait for the previous operation to complete. Change-Id: Id4d54edfe920aeb4a534980cb0cc85a56c067a70 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>bb10
parent
c6c6e01e89
commit
5b78d7fdcf
|
|
@ -1763,9 +1763,7 @@ qint64 QIODevice::write(const QByteArray &data)
|
|||
*/
|
||||
void QIODevicePrivate::write(const char *data, qint64 size)
|
||||
{
|
||||
if (currentWriteChunk != nullptr
|
||||
&& currentWriteChunk->constData() == data
|
||||
&& currentWriteChunk->size() == size) {
|
||||
if (isWriteChunkCached(data, size)) {
|
||||
// We are called from write(const QByteArray &) overload.
|
||||
// So, we can make a shallow copy of chunk.
|
||||
writeBuffer.append(*currentWriteChunk);
|
||||
|
|
|
|||
|
|
@ -185,6 +185,13 @@ public:
|
|||
qint64 skipByReading(qint64 maxSize);
|
||||
void write(const char *data, qint64 size);
|
||||
|
||||
inline bool isWriteChunkCached(const char *data, qint64 size) const
|
||||
{
|
||||
return currentWriteChunk != nullptr
|
||||
&& currentWriteChunk->constData() == data
|
||||
&& currentWriteChunk->size() == size;
|
||||
}
|
||||
|
||||
#ifdef QT_NO_QOBJECT
|
||||
QIODevice *q_ptr = nullptr;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -121,16 +121,35 @@ qint64 QWindowsPipeWriter::bytesToWrite() const
|
|||
}
|
||||
|
||||
/*!
|
||||
Writes data to the pipe.
|
||||
Writes a shallow copy of \a ba to the internal buffer.
|
||||
*/
|
||||
bool QWindowsPipeWriter::write(const QByteArray &ba)
|
||||
{
|
||||
return writeImpl(ba);
|
||||
}
|
||||
|
||||
/*!
|
||||
Writes data to the internal buffer.
|
||||
*/
|
||||
bool QWindowsPipeWriter::write(const char *data, qint64 size)
|
||||
{
|
||||
return writeImpl(data, size);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline bool QWindowsPipeWriter::writeImpl(Args... args)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
if (lastError != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
writeBuffer.append(ba);
|
||||
writeBuffer.append(args...);
|
||||
return writeImplTail(&locker);
|
||||
}
|
||||
|
||||
bool QWindowsPipeWriter::writeImplTail(QMutexLocker<QMutex> *locker)
|
||||
{
|
||||
if (writeSequenceStarted)
|
||||
return true;
|
||||
|
||||
|
|
@ -143,10 +162,10 @@ bool QWindowsPipeWriter::write(const QByteArray &ba)
|
|||
|
||||
if (!winEventActPosted) {
|
||||
winEventActPosted = true;
|
||||
locker.unlock();
|
||||
locker->unlock();
|
||||
QCoreApplication::postEvent(this, new QEvent(QEvent::WinEventAct));
|
||||
} else {
|
||||
locker.unlock();
|
||||
locker->unlock();
|
||||
}
|
||||
|
||||
SetEvent(syncHandle);
|
||||
|
|
@ -232,8 +251,6 @@ void QWindowsPipeWriter::waitCallback(PTP_CALLBACK_INSTANCE instance, PVOID cont
|
|||
bool QWindowsPipeWriter::writeCompleted(DWORD errorCode, DWORD numberOfBytesWritten)
|
||||
{
|
||||
if (errorCode == ERROR_SUCCESS) {
|
||||
Q_ASSERT(numberOfBytesWritten == DWORD(writeBuffer.nextDataBlockSize()));
|
||||
|
||||
bytesWrittenPending = true;
|
||||
pendingBytesWrittenValue += numberOfBytesWritten;
|
||||
writeBuffer.free(numberOfBytesWritten);
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ public:
|
|||
~QWindowsPipeWriter();
|
||||
|
||||
bool write(const QByteArray &ba);
|
||||
bool write(const char *data, qint64 size);
|
||||
void stop();
|
||||
bool waitForWrite(int msecs);
|
||||
bool checkForWrite() { return consumePendingAndEmit(false); }
|
||||
|
|
@ -83,6 +84,10 @@ protected:
|
|||
bool event(QEvent *e) override;
|
||||
|
||||
private:
|
||||
template <typename... Args>
|
||||
inline bool writeImpl(Args... args);
|
||||
bool writeImplTail(QMutexLocker<QMutex> *locker);
|
||||
|
||||
void startAsyncWriteLocked();
|
||||
static void CALLBACK waitCallback(PTP_CALLBACK_INSTANCE instance, PVOID context,
|
||||
PTP_WAIT wait, TP_WAIT_RESULT waitResult);
|
||||
|
|
|
|||
|
|
@ -136,7 +136,6 @@ public:
|
|||
qint64 pipeWriterBytesToWrite() const;
|
||||
void _q_canRead();
|
||||
void _q_bytesWritten(qint64 bytes);
|
||||
void writeToSocket();
|
||||
void _q_pipeClosed();
|
||||
void _q_winError(ulong windowsError, const QString &function);
|
||||
HANDLE handle;
|
||||
|
|
|
|||
|
|
@ -157,7 +157,6 @@ QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
|
|||
emittedReadyRead(false),
|
||||
emittedBytesWritten(false)
|
||||
{
|
||||
writeBufferChunkSize = QIODEVICE_BUFFERSIZE;
|
||||
}
|
||||
|
||||
QLocalSocketPrivate::~QLocalSocketPrivate()
|
||||
|
|
@ -276,13 +275,18 @@ qint64 QLocalSocket::writeData(const char *data, qint64 len)
|
|||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
d->write(data, len);
|
||||
|
||||
if (!d->pipeWriter) {
|
||||
d->pipeWriter = new QWindowsPipeWriter(d->handle, this);
|
||||
QObjectPrivate::connect(d->pipeWriter, &QWindowsPipeWriter::bytesWritten,
|
||||
d, &QLocalSocketPrivate::_q_bytesWritten);
|
||||
}
|
||||
d->writeToSocket();
|
||||
|
||||
if (d->isWriteChunkCached(data, len))
|
||||
d->pipeWriter->write(*(d->currentWriteChunk));
|
||||
else
|
||||
d->pipeWriter->write(data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
@ -340,7 +344,7 @@ qint64 QLocalSocket::bytesAvailable() const
|
|||
qint64 QLocalSocket::bytesToWrite() const
|
||||
{
|
||||
Q_D(const QLocalSocket);
|
||||
return d->writeBuffer.size() + d->pipeWriterBytesToWrite();
|
||||
return d->pipeWriterBytesToWrite();
|
||||
}
|
||||
|
||||
bool QLocalSocket::canReadLine() const
|
||||
|
|
@ -389,7 +393,6 @@ void QLocalSocket::disconnectFromServer()
|
|||
// It must be destroyed before close() to prevent an infinite loop.
|
||||
delete d->pipeWriter;
|
||||
d->pipeWriter = 0;
|
||||
d->writeBuffer.clear();
|
||||
}
|
||||
|
||||
flush();
|
||||
|
|
@ -434,21 +437,8 @@ void QLocalSocketPrivate::_q_bytesWritten(qint64 bytes)
|
|||
QScopedValueRollback<bool> guard(emittedBytesWritten, true);
|
||||
emit q->bytesWritten(bytes);
|
||||
}
|
||||
if (writeBuffer.isEmpty()) {
|
||||
if (state == QLocalSocket::ClosingState && pipeWriterBytesToWrite() == 0)
|
||||
q->close();
|
||||
} else {
|
||||
writeToSocket();
|
||||
}
|
||||
}
|
||||
|
||||
void QLocalSocketPrivate::writeToSocket()
|
||||
{
|
||||
Q_ASSERT(pipeWriter);
|
||||
Q_ASSERT(!writeBuffer.isEmpty());
|
||||
|
||||
if (!pipeWriter->isWriteOperationActive())
|
||||
pipeWriter->write(writeBuffer.read());
|
||||
if (state == QLocalSocket::ClosingState && pipeWriterBytesToWrite() == 0)
|
||||
q->close();
|
||||
}
|
||||
|
||||
qintptr QLocalSocket::socketDescriptor() const
|
||||
|
|
@ -489,9 +479,6 @@ bool QLocalSocket::waitForDisconnected(int msecs)
|
|||
|
||||
QDeadlineTimer deadline(msecs);
|
||||
while (!d->pipeReader->isPipeClosed()) {
|
||||
if (!d->writeBuffer.isEmpty())
|
||||
d->writeToSocket();
|
||||
|
||||
QSocketPoller poller(*d);
|
||||
if (!poller.poll(deadline))
|
||||
return false;
|
||||
|
|
@ -525,9 +512,6 @@ bool QLocalSocket::waitForReadyRead(int msecs)
|
|||
|
||||
QDeadlineTimer deadline(msecs);
|
||||
while (!d->pipeReader->isPipeClosed()) {
|
||||
if (!d->writeBuffer.isEmpty())
|
||||
d->writeToSocket();
|
||||
|
||||
QSocketPoller poller(*d);
|
||||
if (poller.waitForClose || !poller.poll(deadline))
|
||||
return false;
|
||||
|
|
@ -551,11 +535,8 @@ bool QLocalSocket::waitForBytesWritten(int msecs)
|
|||
|
||||
QDeadlineTimer deadline(msecs);
|
||||
while (!d->pipeReader->isPipeClosed()) {
|
||||
if (!d->writeBuffer.isEmpty()) {
|
||||
d->writeToSocket();
|
||||
} else if (d->pipeWriterBytesToWrite() == 0) {
|
||||
if (bytesToWrite() == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
QSocketPoller poller(*d);
|
||||
if (!poller.poll(deadline))
|
||||
|
|
|
|||
Loading…
Reference in New Issue