From 1a57a4974be9dbdeedef6f5c6eb4332eecf6f0c9 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Fri, 2 Jul 2021 17:31:26 +0300 Subject: [PATCH] QLocalSocket/Win: reimplement skipData() function The base implementation discards the data by reading into a dummy buffer, which is slower than necessary. Change-Id: Iabf0c4a25746af6cac5b61d7bda66d89501c808c Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qwindowspipereader.cpp | 19 +++++++ src/corelib/io/qwindowspipereader_p.h | 1 + src/network/socket/qlocalsocket_win.cpp | 7 ++- .../socket/qlocalsocket/tst_qlocalsocket.cpp | 55 +++++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index c3ac51df949..5415ad7830e 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -232,6 +232,25 @@ qint64 QWindowsPipeReader::readLine(char *data, qint64 maxlen) return readSoFar; } +/*! + Skips up to \c{maxlen} bytes from the internal read buffer. + */ +qint64 QWindowsPipeReader::skip(qint64 maxlen) +{ + QMutexLocker locker(&mutex); + + const qint64 skippedSoFar = readBuffer.skip(qMin(actualReadBufferSize, maxlen)); + actualReadBufferSize -= skippedSoFar; + + if (!pipeBroken) { + startAsyncReadHelper(&locker); + if (skippedSoFar == 0) + return -2; // signal EWOULDBLOCK + } + + return skippedSoFar; +} + /*! Returns \c true if a complete line of data can be read from the buffer. */ diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h index e2190d67d92..5eb62cb393d 100644 --- a/src/corelib/io/qwindowspipereader_p.h +++ b/src/corelib/io/qwindowspipereader_p.h @@ -79,6 +79,7 @@ public: qint64 bytesAvailable() const; qint64 read(char *data, qint64 maxlen); qint64 readLine(char *data, qint64 maxlen); + qint64 skip(qint64 maxlen); bool canReadLine() const; DWORD checkPipeState(); bool checkForReadyRead() { return consumePendingAndEmit(false); } diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp index 89901533af1..e430f642db9 100644 --- a/src/network/socket/qlocalsocket_win.cpp +++ b/src/network/socket/qlocalsocket_win.cpp @@ -277,7 +277,12 @@ qint64 QLocalSocket::readLineData(char *data, qint64 maxSize) qint64 QLocalSocket::skipData(qint64 maxSize) { - return QIODevice::skipData(maxSize); + Q_D(QLocalSocket); + + if (!maxSize) + return 0; + + return transformPipeReaderResult(d->pipeReader->skip(maxSize)); } qint64 QLocalSocket::writeData(const char *data, qint64 len) diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp index 8ec41a760ab..cec783985d0 100644 --- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp @@ -95,6 +95,9 @@ private slots: void readLine_data(); void readLine(); + void skip_data(); + void skip(); + void readBufferOverflow(); void simpleCommandProtocol1(); @@ -806,6 +809,58 @@ void tst_QLocalSocket::readLine() QCOMPARE(result, output); } +void tst_QLocalSocket::skip_data() +{ + QTest::addColumn("data"); + QTest::addColumn("read"); + QTest::addColumn("skip"); + QTest::addColumn("skipped"); + QTest::addColumn("expect"); + + QByteArray bigData; + bigData.fill('a', 20000); + bigData[10001] = 'x'; + + QTest::newRow("small_data") << QByteArray("abcdefghij") << 3 << 6 << 6 << 'j'; + QTest::newRow("big_data") << bigData << 1 << 10000 << 10000 << 'x'; + QTest::newRow("beyond_the_end") << bigData << 1 << 20000 << 19999 << '\0'; +} + +void tst_QLocalSocket::skip() +{ + QFETCH(QByteArray, data); + QFETCH(int, read); + QFETCH(int, skip); + QFETCH(int, skipped); + QFETCH(char, expect); + char lastChar = '\0'; + + const QString serverName = QLatin1String("tst_localsocket"); + LocalServer server; + QVERIFY(server.listen(serverName)); + + LocalSocket client; + client.connectToServer(serverName); + QVERIFY(server.waitForNewConnection()); + QLocalSocket *serverSocket = server.nextPendingConnection(); + QVERIFY(serverSocket); + QCOMPARE(client.state(), QLocalSocket::ConnectedState); + + QCOMPARE(serverSocket->write(data), data.size()); + while (serverSocket->waitForBytesWritten()) + QVERIFY(client.waitForReadyRead()); + QCOMPARE(serverSocket->bytesToWrite(), qint64(0)); + serverSocket->close(); + QVERIFY(client.waitForDisconnected()); + + for (int i = 0; i < read; ++i) + client.getChar(nullptr); + + QCOMPARE(client.skip(skip), skipped); + client.getChar(&lastChar); + QCOMPARE(lastChar, expect); +} + void tst_QLocalSocket::readBufferOverflow() { const int readBufferSize = 128;