-
Bug
-
Resolution: Done
-
P1: Critical
-
5.7.0 Beta
-
None
-
WinRT
-
-
fc35f9496439d7a236f7be1eecae53ad6ddd9112
If more than 1 datagram is read by single readyRead fire, it will still fire n many readyRead even though there are no pending datagrams and since hasPendingDatagrams() is false and readDatagram() is never called the setReadNotificationEnabled(true) is never called causing a indefinite stall.
This happens because readyRead is emitted in QNativeSocketEnginePrivate::handleNewDatagram running on a foreign thread causing multiple readyRead signals to be queued.
Minimal example (can be in the same app instance)
// receiver
auto receiver = new QUdpSocket(&app);
if (!receiver->bind()) {
qFatal("bind() failed");
}
auto localPort = receiver->localPort();
QObject::connect(receiver,&QUdpSocket::readyRead, receiver, [receiver]() {
int count = 0;
while (receiver->hasPendingDatagrams()) {
QByteArray data(receiver->pendingDatagramSize(), Qt::Uninitialized);
receiver->readDatagram(data.data(), data.size());
++count;
}
qDebug("received %d datagrams", count);
});
// sender
auto sender = new QUdpSocket(&app);
auto timer = new QTimer(&app);
timer->setInterval(1000);
timer->setSingleShot(false);
QObject::connect(timer, &QTimer::timeout, sender, [sender,localPort]() {
static int burstSize = 1;
qDebug("sending %d datagram burst", burstSize);
for (int i=0; i<burstSize; ++i) {
sender->writeDatagram({},QHostAddress::LocalHost, localPort);
}
burstSize = qMin(burstSize+1,3);
});
timer->start();
Output under WinRT
sending 1 datagram burst
received 1 datagrams
sending 2 datagram burst
received 2 datagrams
received 0 datagrams < false readyRead
sending 3 datagram burst
sending 3 datagram burst
sending 3 datagram burst
...
Output under all other platforms (Linux, OSX, Win32 at least)
sending 1 datagram burst received 1 datagrams sending 2 datagram burst received 2 datagrams sending 3 datagram burst received 3 datagrams sending 3 datagram burst received 3 datagrams sending 3 datagram burst received 3 datagrams ...
Workaround
while (receiver->hasPendingDatagrams()) {
QByteArray data(receiver->pendingDatagramSize(), Qt::Uninitialized);
receiver->readDatagram(data.data(), data.size());
// ...
#ifdef Q_OS_WINRT
break; // we'll get multiple readReady signals use those to avoid indefinitely stop future readyReads
#endif
}