summaryrefslogtreecommitdiffstats
path: root/src/network/socket
diff options
context:
space:
mode:
authorAlex Trotsenko <alex1973tr@gmail.com>2021-08-20 19:15:26 +0300
committerAlex Trotsenko <alex1973tr@gmail.com>2021-09-02 08:47:11 +0300
commit5d68858ba78f485e19e2c36b15f86c8cc8435ff9 (patch)
tree997ed53bc0360239a684daeb9fdab838325d13fe /src/network/socket
parent9a4c98e55659b32db984612e6247ac193812a502 (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.cpp44
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;