When does it actually become false
-
The outer loop iterates while the
list
pointer always points to the last element ofsignalVector
. It might seem likelist != &signalVector->at(-1)
would hardly ever evaluate tofalse
. When does it actually becomefalse
, 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); }
}
-
Please format your code with the appropriate code tags so it gets readable.
-
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.