Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. General talk
  3. Qt 6
  4. When does it actually become false
Forum Updated to NodeBB v4.3 + New Features

When does it actually become false

Scheduled Pinned Locked Moved Unsolved Qt 6
3 Posts 3 Posters 504 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    Tricoffee
    wrote on last edited by Tricoffee
    #1

    The outer loop iterates while the list pointer always points to the last element of signalVector. It might seem like list != &signalVector->at(-1) would hardly ever evaluate to false. When does it actually become false, and which part of the code triggers it?

    template <bool callbacks_enabled>
    void doActivate(QObject *sender, int signal_index, void **argv)
    {
    QObjectPrivate *sp = QObjectPrivate::get(sender);

    if (sp->blockSig)
        return;
    
    Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
    
    if (sp->isDeclarativeSignalConnected(signal_index)
            && QAbstractDeclarativeData::signalEmitted) {
        Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
        QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
                                                signal_index, argv);
    }
    
    const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
    
    void *empty_argv[] = { nullptr };
    if (!argv)
        argv = empty_argv;
    
    if (!sp->maybeSignalConnected(signal_index)) {
        // The possible declarative connection is done, and nothing else is connected
        if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
            signal_spy_set->signal_begin_callback(sender, signal_index, argv);
        if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
            signal_spy_set->signal_end_callback(sender, signal_index);
        return;
    }
    
    if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
        signal_spy_set->signal_begin_callback(sender, signal_index, argv);
    
    bool senderDeleted = false;
    {
    Q_ASSERT(sp->connections.loadAcquire());
    QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadRelaxed());
    QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
    
    const QObjectPrivate::ConnectionList *list;
    if (signal_index < signalVector->count())
        list = &signalVector->at(signal_index);
    else
        list = &signalVector->at(-1);
    
    Qt::HANDLE currentThreadId = QThread::currentThreadId();
    bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
    
    // We need to check against the highest connection id to ensure that signals added
    // during the signal emission are not emitted in this emission.
    uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
    do {
        QObjectPrivate::Connection *c = list->first.loadRelaxed();
        if (!c)
            continue;
    
        do {
            QObject * const receiver = c->receiver.loadRelaxed();
            if (!receiver)
                continue;
    
            QThreadData *td = c->receiverThreadData.loadRelaxed();
            if (!td)
                continue;
    
            bool receiverInSameThread;
            if (inSenderThread) {
                receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
            } else {
                // need to lock before reading the threadId, because moveToThread() could interfere
                QMutexLocker lock(signalSlotLock(receiver));
                receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
            }
    
    
            // determine if this connection should be sent immediately or
            // put into the event queue
            if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
                || (c->connectionType == Qt::QueuedConnection)) {
                queued_activate(sender, signal_index, c, argv);
                continue;
    

    #if QT_CONFIG(thread)
    } else if (c->connectionType == Qt::BlockingQueuedConnection) {
    if (receiverInSameThread) {
    qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
    "Sender is %s(%p), receiver is %s(%p)",
    sender->metaObject()->className(), sender,
    receiver->metaObject()->className(), receiver);
    }

                if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
                    continue;
    
                QSemaphore semaphore;
                {
                    QBasicMutexLocker locker(signalSlotLock(receiver));
                    if (!c->isSingleShot && !c->receiver.loadAcquire())
                        continue;
                    QMetaCallEvent *ev = c->isSlotObject ?
                        new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
                        new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
                                           sender, signal_index, argv, &semaphore);
                    QCoreApplication::postEvent(receiver, ev);
                }
                semaphore.acquire();
                continue;
    

    #endif
    }

            if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
                continue;
    
            QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);
    
            if (c->isSlotObject) {
                SlotObjectGuard obj{c->slotObj};
    
                {
                    Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
                    obj->call(receiver, argv);
                }
            } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
                //we compare the vtable to make sure we are not in the destructor of the object.
                const int method_relative = c->method_relative;
                const auto callFunction = c->callFunction;
                const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
                if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
                    signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
    
                {
                    Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
                    callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
                }
    
                if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
                    signal_spy_set->slot_end_callback(receiver, methodIndex);
            } else {
                const int method = c->method_relative + c->method_offset;
    
                if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
                    signal_spy_set->slot_begin_callback(receiver, method, argv);
                }
    
                {
                    Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
                    QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
                }
    
                if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
                    signal_spy_set->slot_end_callback(receiver, method);
            }
        } while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);
    
    } while (list != &signalVector->at(-1) &&
        //start over for all signals;
        ((list = &signalVector->at(-1)), true));
    
        if (connections->currentConnectionId.loadRelaxed() == 0)
            senderDeleted = true;
    }
    if (!senderDeleted) {
        sp->connections.loadRelaxed()->cleanOrphanedConnections(sender);
    
        if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
            signal_spy_set->signal_end_callback(sender, signal_index);
    }
    

    }

    Christian EhrlicherC 1 Reply Last reply
    0
    • T Tricoffee

      The outer loop iterates while the list pointer always points to the last element of signalVector. It might seem like list != &signalVector->at(-1) would hardly ever evaluate to false. When does it actually become false, and which part of the code triggers it?

      template <bool callbacks_enabled>
      void doActivate(QObject *sender, int signal_index, void **argv)
      {
      QObjectPrivate *sp = QObjectPrivate::get(sender);

      if (sp->blockSig)
          return;
      
      Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
      
      if (sp->isDeclarativeSignalConnected(signal_index)
              && QAbstractDeclarativeData::signalEmitted) {
          Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
          QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
                                                  signal_index, argv);
      }
      
      const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
      
      void *empty_argv[] = { nullptr };
      if (!argv)
          argv = empty_argv;
      
      if (!sp->maybeSignalConnected(signal_index)) {
          // The possible declarative connection is done, and nothing else is connected
          if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
              signal_spy_set->signal_begin_callback(sender, signal_index, argv);
          if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
              signal_spy_set->signal_end_callback(sender, signal_index);
          return;
      }
      
      if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
          signal_spy_set->signal_begin_callback(sender, signal_index, argv);
      
      bool senderDeleted = false;
      {
      Q_ASSERT(sp->connections.loadAcquire());
      QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadRelaxed());
      QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
      
      const QObjectPrivate::ConnectionList *list;
      if (signal_index < signalVector->count())
          list = &signalVector->at(signal_index);
      else
          list = &signalVector->at(-1);
      
      Qt::HANDLE currentThreadId = QThread::currentThreadId();
      bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
      
      // We need to check against the highest connection id to ensure that signals added
      // during the signal emission are not emitted in this emission.
      uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
      do {
          QObjectPrivate::Connection *c = list->first.loadRelaxed();
          if (!c)
              continue;
      
          do {
              QObject * const receiver = c->receiver.loadRelaxed();
              if (!receiver)
                  continue;
      
              QThreadData *td = c->receiverThreadData.loadRelaxed();
              if (!td)
                  continue;
      
              bool receiverInSameThread;
              if (inSenderThread) {
                  receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
              } else {
                  // need to lock before reading the threadId, because moveToThread() could interfere
                  QMutexLocker lock(signalSlotLock(receiver));
                  receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
              }
      
      
              // determine if this connection should be sent immediately or
              // put into the event queue
              if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
                  || (c->connectionType == Qt::QueuedConnection)) {
                  queued_activate(sender, signal_index, c, argv);
                  continue;
      

      #if QT_CONFIG(thread)
      } else if (c->connectionType == Qt::BlockingQueuedConnection) {
      if (receiverInSameThread) {
      qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
      "Sender is %s(%p), receiver is %s(%p)",
      sender->metaObject()->className(), sender,
      receiver->metaObject()->className(), receiver);
      }

                  if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
                      continue;
      
                  QSemaphore semaphore;
                  {
                      QBasicMutexLocker locker(signalSlotLock(receiver));
                      if (!c->isSingleShot && !c->receiver.loadAcquire())
                          continue;
                      QMetaCallEvent *ev = c->isSlotObject ?
                          new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
                          new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
                                             sender, signal_index, argv, &semaphore);
                      QCoreApplication::postEvent(receiver, ev);
                  }
                  semaphore.acquire();
                  continue;
      

      #endif
      }

              if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
                  continue;
      
              QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);
      
              if (c->isSlotObject) {
                  SlotObjectGuard obj{c->slotObj};
      
                  {
                      Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
                      obj->call(receiver, argv);
                  }
              } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
                  //we compare the vtable to make sure we are not in the destructor of the object.
                  const int method_relative = c->method_relative;
                  const auto callFunction = c->callFunction;
                  const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
                  if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
                      signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
      
                  {
                      Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
                      callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
                  }
      
                  if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
                      signal_spy_set->slot_end_callback(receiver, methodIndex);
              } else {
                  const int method = c->method_relative + c->method_offset;
      
                  if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
                      signal_spy_set->slot_begin_callback(receiver, method, argv);
                  }
      
                  {
                      Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
                      QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
                  }
      
                  if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
                      signal_spy_set->slot_end_callback(receiver, method);
              }
          } while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);
      
      } while (list != &signalVector->at(-1) &&
          //start over for all signals;
          ((list = &signalVector->at(-1)), true));
      
          if (connections->currentConnectionId.loadRelaxed() == 0)
              senderDeleted = true;
      }
      if (!senderDeleted) {
          sp->connections.loadRelaxed()->cleanOrphanedConnections(sender);
      
          if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
              signal_spy_set->signal_end_callback(sender, signal_index);
      }
      

      }

      Christian EhrlicherC Online
      Christian EhrlicherC Online
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Please format your code with the appropriate code tags so it gets readable.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      1
      • S Offline
        S Offline
        SimonSchroeder
        wrote on last edited by
        #3

        The source code for SignalVector::at states:

        ConnectionList &at(int i)
        {
            return reinterpret_cast<ConnectionList *>(this + 1)[i + 1];
        }
        

        So, basically signalVector->at(-1) could be something like the first element of the array. Because Qt uses a lot of tricks (e.g. this+1) in this internal code, I am not willing to figure it out exactly. Have a look at the source yourself if you want to figure this out.

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved