diff options
author | Alex Trotsenko <alex1973tr@gmail.com> | 2021-08-20 19:15:26 +0300 |
---|---|---|
committer | Alex Trotsenko <alex1973tr@gmail.com> | 2021-09-02 08:47:11 +0300 |
commit | 5d68858ba78f485e19e2c36b15f86c8cc8435ff9 (patch) | |
tree | 997ed53bc0360239a684daeb9fdab838325d13fe /src/network/socket | |
parent | 9a4c98e55659b32db984612e6247ac193812a502 (diff) |
QLocalSocket/Win: fix waitFor...() functions for write-only socket
There were several issues with the socket state checking when the pipe
reader is not running:
- the number of object handles in the WaitForMultipleObjectsEx()
call might have been zero;
- a call to the waitForDisconnected(-1) might have hung;
- we did not perform a loop iteration for the waitFor...(0) calls,
so disconnect detection was unreliable.
These issues are related to the same code, so they don't seem to be
addressable separately.
Change-Id: I3bca872bb4191e6a7d38a693d81f7981af7fe145
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Diffstat (limited to 'src/network/socket')
-rw-r--r-- | src/network/socket/qlocalsocket_win.cpp | 44 |
1 files changed, 36 insertions, 8 deletions
diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp index 229efe0226..0a39e84c07 100644 --- a/src/network/socket/qlocalsocket_win.cpp +++ b/src/network/socket/qlocalsocket_win.cpp @@ -48,24 +48,38 @@ struct QSocketPoller { QSocketPoller(const QLocalSocketPrivate &socket); + qint64 getRemainingTime(const QDeadlineTimer &deadline) const; bool poll(const QDeadlineTimer &deadline); enum { maxHandles = 2 }; HANDLE handles[maxHandles]; DWORD handleCount = 0; bool waitForClose = false; + bool writePending = false; }; QSocketPoller::QSocketPoller(const QLocalSocketPrivate &socket) { - if (socket.pipeWriter) + if (socket.pipeWriter && socket.pipeWriter->bytesToWrite() != 0) { handles[handleCount++] = socket.pipeWriter->syncEvent(); + writePending = true; + } if (socket.pipeReader->isReadOperationActive()) handles[handleCount++] = socket.pipeReader->syncEvent(); else waitForClose = true; } +qint64 QSocketPoller::getRemainingTime(const QDeadlineTimer &deadline) const +{ + const qint64 sleepTime = 10; + qint64 remainingTime = deadline.remainingTime(); + if (waitForClose && (remainingTime > sleepTime || remainingTime == -1)) + return sleepTime; + + return remainingTime; +} + /*! Waits until new data is available for reading or write operation completes. Returns \c true, if we need to check pipe workers; @@ -77,9 +91,8 @@ QSocketPoller::QSocketPoller(const QLocalSocketPrivate &socket) */ bool QSocketPoller::poll(const QDeadlineTimer &deadline) { - const qint64 sleepTime = 10; - QDeadlineTimer timer(waitForClose ? qMin(deadline.remainingTime(), sleepTime) - : deadline.remainingTime()); + Q_ASSERT(handleCount != 0); + QDeadlineTimer timer(getRemainingTime(deadline)); DWORD waitRet; do { @@ -88,7 +101,7 @@ bool QSocketPoller::poll(const QDeadlineTimer &deadline) } while (waitRet == WAIT_IO_COMPLETION); if (waitRet == WAIT_TIMEOUT) - return !deadline.hasExpired(); + return waitForClose || !deadline.hasExpired(); return waitRet - WAIT_OBJECT_0 < handleCount; } @@ -473,10 +486,22 @@ bool QLocalSocket::waitForDisconnected(int msecs) } QDeadlineTimer deadline(msecs); + bool wasChecked = false; while (!d->pipeReader->isPipeClosed()) { + if (wasChecked && deadline.hasExpired()) + return false; + QSocketPoller poller(*d); - if (!poller.poll(deadline)) + // The first parameter of the WaitForMultipleObjectsEx() call cannot + // be zero. So we have to call SleepEx() here. + if (!poller.writePending && poller.waitForClose) { + // Prevent waiting on the first pass, if both the pipe reader + // and the pipe writer are inactive. + if (wasChecked) + SleepEx(poller.getRemainingTime(deadline), TRUE); + } else if (!poller.poll(deadline)) { return false; + } if (d->pipeWriter) d->pipeWriter->checkForWrite(); @@ -487,6 +512,7 @@ bool QLocalSocket::waitForDisconnected(int msecs) d->pipeReader->checkPipeState(); d->pipeReader->checkForReadyRead(); + wasChecked = true; } d->_q_pipeClosed(); return true; @@ -529,12 +555,13 @@ bool QLocalSocket::waitForBytesWritten(int msecs) return false; QDeadlineTimer deadline(msecs); + bool wasChecked = false; while (!d->pipeReader->isPipeClosed()) { - if (bytesToWrite() == 0) + if (wasChecked && deadline.hasExpired()) return false; QSocketPoller poller(*d); - if (!poller.poll(deadline)) + if (!poller.writePending || !poller.poll(deadline)) return false; Q_ASSERT(d->pipeWriter); @@ -545,6 +572,7 @@ bool QLocalSocket::waitForBytesWritten(int msecs) d->pipeReader->checkPipeState(); d->pipeReader->checkForReadyRead(); + wasChecked = true; } d->_q_pipeClosed(); return false; |