Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-53472

WinRT QUdpSocket readyRead misfire

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P1: Critical
    • 5.8.0 RC
    • 5.7.0 Beta
    • Network: Sockets
    • None
    • WinRT
    • 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
              }
      

      Attachments

        For Gerrit Dashboard: QTBUG-53472
        # Subject Branch Project Status CR V

        Activity

          People

            owolff Oliver Wolff
            kristjanbb Kristján Birgisson
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes