Details
-
Bug
-
Resolution: Done
-
P1: Critical
-
5.7.0 Beta
-
None
-
WinRT
-
-
fc35f9496439d7a236f7be1eecae53ad6ddd9112
Description
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 }