diff options
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 630 |
1 files changed, 276 insertions, 354 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 15955e1665..759ccaacd8 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -77,6 +77,12 @@ QT_BEGIN_NAMESPACE static int DIRECT_CONNECTION_ONLY = 0; +Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_set = Q_BASIC_ATOMIC_INITIALIZER(nullptr); + +void qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set) +{ + qt_signal_spy_callback_set.store(callback_set); +} QDynamicMetaObjectData::~QDynamicMetaObjectData() { @@ -146,10 +152,9 @@ static QBasicMutex _q_ObjectMutexPool[131]; * \internal * mutex to be locked when accessing the connectionlists or the senders list */ -static inline QMutex *signalSlotLock(const QObject *o) +static inline QBasicMutex *signalSlotLock(const QObject *o) { - return static_cast<QMutex *>(&_q_ObjectMutexPool[ - uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]); + return &_q_ObjectMutexPool[uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]; } #if QT_VERSION < 0x60000 @@ -160,39 +165,6 @@ extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) {} #endif -struct QConnectionSenderSwitcher { - QObject *receiver; - QObjectPrivate::Sender *previousSender; - QObjectPrivate::Sender currentSender; - bool switched; - - inline QConnectionSenderSwitcher() : switched(false) {} - - inline QConnectionSenderSwitcher(QObject *receiver, QObject *sender, int signal_absolute_id) - { - switchSender(receiver, sender, signal_absolute_id); - } - - inline void switchSender(QObject *receiver, QObject *sender, int signal_absolute_id) - { - this->receiver = receiver; - currentSender.sender = sender; - currentSender.signal = signal_absolute_id; - currentSender.ref = 1; - previousSender = QObjectPrivate::setCurrentSender(receiver, ¤tSender); - switched = true; - } - - inline ~QConnectionSenderSwitcher() - { - if (switched) - QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); - } -private: - Q_DISABLE_COPY(QConnectionSenderSwitcher) -}; - - void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = 0; void (*QAbstractDeclarativeData::destroyed_qml1)(QAbstractDeclarativeData *, QObject *) = 0; void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0; @@ -209,7 +181,7 @@ QMetaObject *QObjectData::dynamicMetaObject() const } QObjectPrivate::QObjectPrivate(int version) - : threadData(0), connectionLists(0), senders(0), currentSender(0), currentChildBeingDeleted(0) + : threadData(0), currentChildBeingDeleted(0) { #ifdef QT_BUILD_INTERNAL // Don't check the version parameter in internal builds. @@ -232,7 +204,6 @@ QObjectPrivate::QObjectPrivate(int version) receiveChildEvents = true; postedEvents = 0; extraData = 0; - connectedSignals[0] = connectedSignals[1] = 0; metaObject = 0; isWindow = false; deleteLaterCalled = false; @@ -285,59 +256,22 @@ static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int } } -/* - This vector contains the all connections from an object. - - Each object may have one vector containing the lists of - connections for a given signal. The index in the vector correspond - to the signal index. The signal index is the one returned by - QObjectPrivate::signalIndex (not QMetaObject::indexOfSignal). - Negative index means connections to all signals. - - This vector is protected by the object mutex (signalSlotMutexes()) - - Each Connection is also part of a 'senders' linked list. The mutex - of the receiver must be locked when touching the pointers of this - linked list. -*/ -class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList> -{ -public: - bool orphaned; //the QObject owner of this vector has been destroyed while the vector was inUse - bool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet - int inUse; //number of functions that are currently accessing this object or its connections - QObjectPrivate::ConnectionList allsignals; - - QObjectConnectionListVector() - : QVector<QObjectPrivate::ConnectionList>(), orphaned(false), dirty(false), inUse(0) - { } - - QObjectPrivate::ConnectionList &operator[](int at) - { - if (at < 0) - return allsignals; - return QVector<QObjectPrivate::ConnectionList>::operator[](at); - } -}; - // Used by QAccessibleWidget bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const { Q_Q(const QObject); int signal_index = signalIndex(signal); - if (signal_index < 0) + ConnectionData *cd = connections.load(); + if (signal_index < 0 || !cd) return false; - QMutexLocker locker(signalSlotLock(q)); - if (connectionLists) { - if (signal_index < connectionLists->count()) { - const QObjectPrivate::Connection *c = - connectionLists->at(signal_index).first; - - while (c) { - if (c->receiver == receiver) - return true; - c = c->nextConnectionList; - } + QBasicMutexLocker locker(signalSlotLock(q)); + if (signal_index < cd->signalVector.count()) { + const QObjectPrivate::Connection *c = cd->signalVector.at(signal_index).first; + + while (c) { + if (c->receiver == receiver) + return true; + c = c->nextConnectionList; } } return false; @@ -349,18 +283,17 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const Q_Q(const QObject); QObjectList returnValue; int signal_index = signalIndex(signal); - if (signal_index < 0) + ConnectionData *cd = connections.load(); + if (signal_index < 0 || !cd) return returnValue; - QMutexLocker locker(signalSlotLock(q)); - if (connectionLists) { - if (signal_index < connectionLists->count()) { - const QObjectPrivate::Connection *c = connectionLists->at(signal_index).first; - - while (c) { - if (c->receiver) - returnValue << c->receiver; - c = c->nextConnectionList; - } + QBasicMutexLocker locker(signalSlotLock(q)); + if (signal_index < cd->signalVector.count()) { + const QObjectPrivate::Connection *c = cd->signalVector.at(signal_index).first; + + while (c) { + if (c->receiver) + returnValue << c->receiver; + c = c->nextConnectionList; } } return returnValue; @@ -370,9 +303,12 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const QObjectList QObjectPrivate::senderList() const { QObjectList returnValue; - QMutexLocker locker(signalSlotLock(q_func())); - for (Connection *c = senders; c; c = c->next) - returnValue << c->sender; + ConnectionData *cd = connections.load(); + if (cd) { + QBasicMutexLocker locker(signalSlotLock(q_func())); + for (Connection *c = cd->senders; c; c = c->next) + returnValue << c->sender; + } return returnValue; } @@ -389,12 +325,12 @@ QObjectList QObjectPrivate::senderList() const void QObjectPrivate::addConnection(int signal, Connection *c) { Q_ASSERT(c->sender == q_ptr); - if (!connectionLists) - connectionLists = new QObjectConnectionListVector(); - if (signal >= connectionLists->count()) - connectionLists->resize(signal + 1); + ensureConnectionData(); + ConnectionData *cd = connections.load(); + if (signal >= cd->signalVector.count()) + cd->signalVector.resize(signal + 1); - ConnectionList &connectionList = (*connectionLists)[signal]; + ConnectionList &connectionList = cd->connectionsForSignal(signal); if (connectionList.last) { connectionList.last->nextConnectionList = c; } else { @@ -404,27 +340,23 @@ void QObjectPrivate::addConnection(int signal, Connection *c) cleanConnectionLists(); - c->prev = &(QObjectPrivate::get(c->receiver)->senders); + QObjectPrivate *rd = QObjectPrivate::get(c->receiver); + rd->ensureConnectionData(); + + c->prev = &(rd->connections.load()->senders); c->next = *c->prev; *c->prev = c; if (c->next) c->next->prev = &c->next; - - if (signal < 0) { - connectedSignals[0] = connectedSignals[1] = ~0; - } else if (signal < (int)sizeof(connectedSignals) * 8) { - connectedSignals[signal >> 5] |= (1 << (signal & 0x1f)); - } } void QObjectPrivate::cleanConnectionLists() { - if (connectionLists->dirty && !connectionLists->inUse) { + ConnectionData *cd = connections.load(); + if (cd->dirty && cd->ref == 1) { // remove broken connections - bool allConnected = false; - for (int signal = -1; signal < connectionLists->count(); ++signal) { - QObjectPrivate::ConnectionList &connectionList = - (*connectionLists)[signal]; + for (int signal = -1; signal < cd->signalVector.count(); ++signal) { + ConnectionList &connectionList = cd->connectionsForSignal(signal); // Set to the last entry in the connection list that was *not* // deleted. This is needed to update the list's last pointer @@ -433,13 +365,11 @@ void QObjectPrivate::cleanConnectionLists() QObjectPrivate::Connection **prev = &connectionList.first; QObjectPrivate::Connection *c = *prev; - bool connected = false; // whether the signal is still connected somewhere while (c) { if (c->receiver) { last = c; prev = &c->nextConnectionList; c = *prev; - connected = true; } else { QObjectPrivate::Connection *next = c->nextConnectionList; *prev = next; @@ -451,19 +381,41 @@ void QObjectPrivate::cleanConnectionLists() // Correct the connection list's last pointer. // As conectionList.last could equal last, this could be a noop connectionList.last = last; + } + cd->dirty = false; + } +} - if (!allConnected && !connected && signal >= 0 - && size_t(signal) < sizeof(connectedSignals) * 8) { - // This signal is no longer connected - connectedSignals[signal >> 5] &= ~(1 << (signal & 0x1f)); - } else if (signal == -1) { - allConnected = connected; - } +/*! \internal + + Returns \c true if the signal with index \a signal_index from object \a sender is connected. + + \a signal_index must be the index returned by QObjectPrivate::signalIndex; +*/ +bool QObjectPrivate::isSignalConnected(uint signalIndex, bool checkDeclarative) const +{ + if (checkDeclarative && isDeclarativeSignalConnected(signalIndex)) + return true; + + ConnectionData *cd = connections.load(); + if (!cd) + return false; + + if (cd->allsignals.first) + return true; + + if (signalIndex < uint(cd->signalVector.count())) { + const QObjectPrivate::Connection *c = cd->signalVector.at(signalIndex).first; + while (c) { + if (c->receiver) + return true; + c = c->nextConnectionList; } - connectionLists->dirty = false; } + return false; } + /*! \internal */ @@ -921,60 +873,50 @@ QObject::~QObject() } } - // set ref to zero to indicate that this object has been deleted - if (d->currentSender != 0) - d->currentSender->ref = 0; - d->currentSender = 0; + QObjectPrivate::ConnectionData *cd = d->connections.load(); + if (cd) { + if (cd->currentSender) { + cd->currentSender->receiverDeleted(); + cd->currentSender = nullptr; + } - if (d->connectionLists || d->senders) { - QMutex *signalSlotMutex = signalSlotLock(this); - QMutexLocker locker(signalSlotMutex); + QBasicMutex *signalSlotMutex = signalSlotLock(this); + QBasicMutexLocker locker(signalSlotMutex); // disconnect all receivers - if (d->connectionLists) { - ++d->connectionLists->inUse; - int connectionListsCount = d->connectionLists->count(); - for (int signal = -1; signal < connectionListsCount; ++signal) { - QObjectPrivate::ConnectionList &connectionList = - (*d->connectionLists)[signal]; - - while (QObjectPrivate::Connection *c = connectionList.first) { - if (!c->receiver) { - connectionList.first = c->nextConnectionList; - c->deref(); - continue; - } - - QMutex *m = signalSlotLock(c->receiver); - bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); - - if (c->receiver) { - *c->prev = c->next; - if (c->next) c->next->prev = c->prev; - } - c->receiver = 0; - if (needToUnlock) - m->unlock(); + int receiverCount = cd->signalVector.count(); + for (int signal = -1; signal < receiverCount; ++signal) { + QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal); + while (QObjectPrivate::Connection *c = connectionList.first) { + if (!c->receiver) { connectionList.first = c->nextConnectionList; - - // The destroy operation must happen outside the lock - if (c->isSlotObject) { - c->isSlotObject = false; - locker.unlock(); - c->slotObj->destroyIfLastRef(); - locker.relock(); - } c->deref(); + continue; } - } - if (!--d->connectionLists->inUse) { - delete d->connectionLists; - } else { - d->connectionLists->orphaned = true; + QBasicMutex *m = signalSlotLock(c->receiver); + bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); + + if (c->receiver) { + *c->prev = c->next; + if (c->next) c->next->prev = c->prev; + } + c->receiver = 0; + if (needToUnlock) + m->unlock(); + + connectionList.first = c->nextConnectionList; + + // The destroy operation must happen outside the lock + if (c->isSlotObject) { + c->isSlotObject = false; + locker.unlock(); + c->slotObj->destroyIfLastRef(); + locker.relock(); + } + c->deref(); } - d->connectionLists = 0; } /* Disconnect all senders: @@ -986,14 +928,15 @@ QObject::~QObject() * thread. That's why we set node->prev to &node, that way, if node is destroyed, node will * be updated. */ - QObjectPrivate::Connection *node = d->senders; + QObjectPrivate::Connection *node = cd->senders; while (node) { + Q_ASSERT(node->receiver); QObject *sender = node->sender; // Send disconnectNotify before removing the connection from sender's connection list. // This ensures any eventual destructor of sender will block on getting receiver's lock // and not finish until we release it. sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index)); - QMutex *m = signalSlotLock(sender); + QBasicMutex *m = signalSlotLock(sender); node->prev = &node; bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); //the node has maybe been removed while the mutex was unlocked in relock? @@ -1004,9 +947,9 @@ QObject::~QObject() continue; } node->receiver = 0; - QObjectConnectionListVector *senderLists = sender->d_func()->connectionLists; - if (senderLists) - senderLists->dirty = true; + QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.load(); + if (senderData) + senderData->dirty = true; QtPrivate::QSlotObjectBase *slotObj = nullptr; if (node->isSlotObject) { @@ -1026,7 +969,12 @@ QObject::~QObject() locker.relock(); } } + + cd->objectDeleted = true; } + if (cd && !cd->ref.deref()) + delete cd; + d->connections.store(nullptr); if (!d->children.isEmpty()) d->deleteChildren(); @@ -1255,7 +1203,11 @@ bool QObject::event(QEvent *e) { QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e); - QConnectionSenderSwitcher sw(this, const_cast<QObject*>(mce->sender()), mce->signalId()); + if (!d_func()->connections.load()) { + QBasicMutexLocker locker(signalSlotLock(this)); + d_func()->ensureConnectionData(); + } + QObjectPrivate::Sender sender(this, const_cast<QObject*>(mce->sender()), mce->signalId()); mce->placeMetaCall(this); break; @@ -1559,9 +1511,11 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData } // the current emitting thread shouldn't restore currentSender after calling moveToThread() - if (currentSender) - currentSender->ref = 0; - currentSender = 0; + ConnectionData *cd = connections.load(); + if (cd && cd->currentSender) { + cd->currentSender->receiverDeleted(); + cd->currentSender = nullptr; + } // set new thread data targetData->ref(); @@ -2370,13 +2324,14 @@ QObject *QObject::sender() const { Q_D(const QObject); - QMutexLocker locker(signalSlotLock(this)); - if (!d->currentSender) - return 0; + QBasicMutexLocker locker(signalSlotLock(this)); + QObjectPrivate::ConnectionData *cd = d->connections.load(); + if (!cd || !cd->currentSender) + return nullptr; - for (QObjectPrivate::Connection *c = d->senders; c; c = c->next) { - if (c->sender == d->currentSender->sender) - return d->currentSender->sender; + for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) { + if (c->sender == cd->currentSender->sender) + return cd->currentSender->sender; } return 0; @@ -2411,14 +2366,15 @@ int QObject::senderSignalIndex() const { Q_D(const QObject); - QMutexLocker locker(signalSlotLock(this)); - if (!d->currentSender) + QBasicMutexLocker locker(signalSlotLock(this)); + QObjectPrivate::ConnectionData *cd = d->connections.load(); + if (!cd || !cd->currentSender) return -1; - for (QObjectPrivate::Connection *c = d->senders; c; c = c->next) { - if (c->sender == d->currentSender->sender) { + for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) { + if (c->sender == cd->currentSender->sender) { // Convert from signal range to method range - return QMetaObjectPrivate::signal(c->sender->metaObject(), d->currentSender->signal).methodIndex(); + return QMetaObjectPrivate::signal(c->sender->metaObject(), cd->currentSender->signal).methodIndex(); } } @@ -2474,15 +2430,14 @@ int QObject::receivers(const char *signal) const signal_index); } - QMutexLocker locker(signalSlotLock(this)); - if (d->connectionLists) { - if (signal_index < d->connectionLists->count()) { - const QObjectPrivate::Connection *c = - d->connectionLists->at(signal_index).first; - while (c) { - receivers += c->receiver ? 1 : 0; - c = c->nextConnectionList; - } + QObjectPrivate::ConnectionData *cd = d->connections.load(); + QBasicMutexLocker locker(signalSlotLock(this)); + if (cd && signal_index < cd->signalVector.count()) { + const QObjectPrivate::Connection *c = + cd->signalVector.at(signal_index).first; + while (c) { + receivers += c->receiver ? 1 : 0; + c = c->nextConnectionList; } } } @@ -2522,22 +2477,8 @@ bool QObject::isSignalConnected(const QMetaMethod &signal) const signalIndex += QMetaObjectPrivate::signalOffset(signal.mobj); - QMutexLocker locker(signalSlotLock(this)); - if (d->connectionLists) { - if (signalIndex < sizeof(d->connectedSignals) * 8 && !d->connectionLists->dirty) - return d->isSignalConnected(signalIndex); - - if (signalIndex < uint(d->connectionLists->count())) { - const QObjectPrivate::Connection *c = - d->connectionLists->at(signalIndex).first; - while (c) { - if (c->receiver) - return true; - c = c->nextConnectionList; - } - } - } - return d->isDeclarativeSignalConnected(signalIndex); + QBasicMutexLocker locker(signalSlotLock(this)); + return d->isSignalConnected(signalIndex, true); } /*! @@ -3300,23 +3241,21 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, int method_offset = rmeta ? rmeta->methodOffset() : 0; Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6); - QObjectPrivate::StaticMetaCallFunction callFunction = - rmeta ? rmeta->d.static_metacall : 0; + QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : nullptr; QOrderedMutexLocker locker(signalSlotLock(sender), signalSlotLock(receiver)); - if (type & Qt::UniqueConnection) { - QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists; - if (connectionLists && connectionLists->count() > signal_index) { - const QObjectPrivate::Connection *c2 = - (*connectionLists)[signal_index].first; + QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.load(); + if (type & Qt::UniqueConnection && scd) { + if (scd->signalVector.count() > signal_index) { + const QObjectPrivate::Connection *c2 = scd->signalVector.at(signal_index).first; int method_index_absolute = method_index + method_offset; while (c2) { if (!c2->isSlotObject && c2->receiver == receiver && c2->method() == method_index_absolute) - return 0; + return nullptr; c2 = c2->nextConnectionList; } } @@ -3380,7 +3319,7 @@ bool QMetaObject::disconnectOne(const QObject *sender, int signal_index, */ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, const QObject *receiver, int method_index, void **slot, - QMutex *senderMutex, DisconnectType disconnectType) + QBasicMutex *senderMutex, DisconnectType disconnectType) { bool success = false; while (c) { @@ -3389,7 +3328,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, && (method_index < 0 || (!c->isSlotObject && c->method() == method_index)) && (slot == 0 || (c->isSlotObject && c->slotObj->compare(slot)))))) { bool needToUnlock = false; - QMutex *receiverMutex = 0; + QBasicMutex *receiverMutex = nullptr; if (c->receiver) { receiverMutex = signalSlotLock(c->receiver); // need to relock this receiver and sender in the correct order @@ -3437,41 +3376,36 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, QObject *s = const_cast<QObject *>(sender); - QMutex *senderMutex = signalSlotLock(sender); - QMutexLocker locker(senderMutex); + QBasicMutex *senderMutex = signalSlotLock(sender); + QBasicMutexLocker locker(senderMutex); - QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists; - if (!connectionLists) + QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.load(); + if (!scd) return false; - // prevent incoming connections changing the connectionLists while unlocked - ++connectionLists->inUse; - bool success = false; - if (signal_index < 0) { - // remove from all connection lists - for (int sig_index = -1; sig_index < connectionLists->count(); ++sig_index) { - QObjectPrivate::Connection *c = - (*connectionLists)[sig_index].first; + { + // prevent incoming connections changing the connections->receivers while unlocked + QObjectPrivate::ConnectionDataPointer connections(scd); + + if (signal_index < 0) { + // remove from all connection lists + for (int sig_index = -1; sig_index < scd->signalVector.count(); ++sig_index) { + QObjectPrivate::Connection *c = scd->connectionsForSignal(sig_index).first; + if (disconnectHelper(c, receiver, method_index, slot, senderMutex, disconnectType)) { + success = true; + scd->dirty = true; + } + } + } else if (signal_index < scd->signalVector.count()) { + QObjectPrivate::Connection *c = scd->signalVector.at(signal_index).first; if (disconnectHelper(c, receiver, method_index, slot, senderMutex, disconnectType)) { success = true; - connectionLists->dirty = true; + scd->dirty = true; } } - } else if (signal_index < connectionLists->count()) { - QObjectPrivate::Connection *c = - (*connectionLists)[signal_index].first; - if (disconnectHelper(c, receiver, method_index, slot, senderMutex, disconnectType)) { - success = true; - connectionLists->dirty = true; - } } - --connectionLists->inUse; - Q_ASSERT(connectionLists->inUse >= 0); - if (connectionLists->orphaned && !connectionLists->inUse) - delete connectionLists; - locker.unlock(); if (success) { QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index); @@ -3590,7 +3524,7 @@ void QMetaObject::connectSlotsByName(QObject *o) \a signal must be in the signal index range (see QObjectPrivate::signalIndex()). */ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv, - QMutexLocker &locker) + QBasicMutexLocker &locker) { const int *argumentTypes = c->argumentTypes.load(); if (!argumentTypes) { @@ -3643,89 +3577,53 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect QCoreApplication::postEvent(c->receiver, ev); } -/*! - \internal - */ -void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, - void **argv) +template <bool callbacks_enabled> +void doActivate(QObject *sender, int signal_index, void **argv) { - activate(sender, QMetaObjectPrivate::signalOffset(m), local_signal_index, argv); -} - -/*! - \internal - */ -void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv) -{ - int signal_index = signalOffset + local_signal_index; + QObjectPrivate *sp = QObjectPrivate::get(sender); - if (sender->d_func()->blockSig) + if (sp->blockSig) return; - if (sender->d_func()->isDeclarativeSignalConnected(signal_index) + if (sp->isDeclarativeSignalConnected(signal_index) && QAbstractDeclarativeData::signalEmitted) { Q_TRACE(QMetaObject_activate_begin_declarative_signal, sender, signal_index); - QAbstractDeclarativeData::signalEmitted(sender->d_func()->declarativeData, sender, + QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender, signal_index, argv); Q_TRACE(QMetaObject_activate_end_declarative_signal, sender, signal_index); } - if (!sender->d_func()->isSignalConnected(signal_index, /*checkDeclarative =*/ false) - && !qt_signal_spy_callback_set.signal_begin_callback - && !qt_signal_spy_callback_set.signal_end_callback - && !Q_TRACE_ENABLED(QMetaObject_activate_begin_signal) - && !Q_TRACE_ENABLED(QMetaObject_activate_end_signal)) { - // The possible declarative connection is done, and nothing else is connected, so: - return; - } + const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.load() : nullptr; void *empty_argv[] = { nullptr }; if (!argv) argv = empty_argv; - if (qt_signal_spy_callback_set.signal_begin_callback != 0) { - qt_signal_spy_callback_set.signal_begin_callback(sender, signal_index, argv); + if (!sp->isSignalConnected(signal_index, false)) { + // 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); + Q_TRACE(QMetaObject_activate_begin_signal, sender, signal_index); + Q_TRACE(QMetaObject_activate_end_signal, sender, signal_index); + 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); Q_TRACE(QMetaObject_activate_begin_signal, sender, signal_index); { - QMutexLocker locker(signalSlotLock(sender)); - struct ConnectionListsRef { - QObjectConnectionListVector *connectionLists; - ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists) - { - if (connectionLists) - ++connectionLists->inUse; - } - ~ConnectionListsRef() - { - if (!connectionLists) - return; - - --connectionLists->inUse; - Q_ASSERT(connectionLists->inUse >= 0); - if (connectionLists->orphaned) { - if (!connectionLists->inUse) - delete connectionLists; - } - } - - QObjectConnectionListVector *operator->() const { return connectionLists; } - }; - ConnectionListsRef connectionLists = sender->d_func()->connectionLists; - if (!connectionLists.connectionLists) { - locker.unlock(); - if (qt_signal_spy_callback_set.signal_end_callback != 0) - qt_signal_spy_callback_set.signal_end_callback(sender, signal_index); - Q_TRACE(QMetaObject_activate_end_signal, sender, signal_index); - return; - } + QBasicMutexLocker locker(signalSlotLock(sender)); + Q_ASSERT(sp->connections); + QObjectPrivate::ConnectionDataPointer connections(sp->connections.load()); const QObjectPrivate::ConnectionList *list; - if (signal_index < connectionLists->count()) - list = &connectionLists->at(signal_index); + if (signal_index < connections->signalVector.count()) + list = &connections->signalVector.at(signal_index); else - list = &connectionLists->allsignals; + list = &connections->allsignals; Qt::HANDLE currentThreadId = QThread::currentThreadId(); @@ -3741,7 +3639,7 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i continue; QObject * const receiver = c->receiver; - const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId.load(); + const bool receiverInSameThread = currentThreadId == QObjectPrivate::get(receiver)->threadData->threadId.load(); // determine if this connection should be sent immediately or // put into the event queue @@ -3769,11 +3667,8 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i #endif } - QConnectionSenderSwitcher sw; + QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index); - if (receiverInSameThread) { - sw.switchSender(receiver, sender, signal_index); - } if (c->isSlotObject) { c->slotObj->ref(); QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj); @@ -3790,57 +3685,85 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i locker.relock(); } 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 methodIndex = c->method(); const int method_relative = c->method_relative; const auto callFunction = c->callFunction; locker.unlock(); - if (qt_signal_spy_callback_set.slot_begin_callback != 0) - qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv); + 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(QMetaObject_activate_begin_slot, receiver, methodIndex); callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv); Q_TRACE(QMetaObject_activate_end_slot, receiver, methodIndex); - if (qt_signal_spy_callback_set.slot_end_callback != 0) - qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex); + if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr) + signal_spy_set->slot_end_callback(receiver, methodIndex); locker.relock(); } else { const int method = c->method_relative + c->method_offset; locker.unlock(); - if (qt_signal_spy_callback_set.slot_begin_callback != 0) { - qt_signal_spy_callback_set.slot_begin_callback(receiver, method, argv); + if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) { + signal_spy_set->slot_begin_callback(receiver, method, argv); } Q_TRACE(QMetaObject_activate_begin_slot, receiver, method); - metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv); + QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv); Q_TRACE(QMetaObject_activate_end_slot, receiver, method); - if (qt_signal_spy_callback_set.slot_end_callback != 0) - qt_signal_spy_callback_set.slot_end_callback(receiver, method); + if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr) + signal_spy_set->slot_end_callback(receiver, method); locker.relock(); } - if (connectionLists->orphaned) + if (connections->objectDeleted) break; } while (c != last && (c = c->nextConnectionList) != 0); - if (connectionLists->orphaned) + if (connections->objectDeleted) break; - } while (list != &connectionLists->allsignals && + } while (list != &connections->allsignals && //start over for all signals; - ((list = &connectionLists->allsignals), true)); + ((list = &connections->allsignals), true)); } - if (qt_signal_spy_callback_set.signal_end_callback != 0) - qt_signal_spy_callback_set.signal_end_callback(sender, signal_index); + if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr) + signal_spy_set->signal_end_callback(sender, signal_index); Q_TRACE(QMetaObject_activate_end_signal, sender, signal_index); + } /*! \internal + */ +void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, + void **argv) +{ + int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m); + + if (Q_UNLIKELY(qt_signal_spy_callback_set.load())) + doActivate<true>(sender, signal_index, argv); + else + doActivate<false>(sender, signal_index, argv); +} + +/*! + \internal + */ +void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv) +{ + int signal_index = signalOffset + local_signal_index; + + if (Q_UNLIKELY(qt_signal_spy_callback_set.load())) + doActivate<true>(sender, signal_index, argv); + else + doActivate<false>(sender, signal_index, argv); + } + +/*! + \internal signal_index comes from indexOfMethod() */ void QMetaObject::activate(QObject *sender, int signal_index, void **argv) @@ -3853,7 +3776,7 @@ void QMetaObject::activate(QObject *sender, int signal_index, void **argv) /*! \internal - Returns the signal index used in the internal connectionLists vector. + Returns the signal index used in the internal connections->receivers vector. It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots. @@ -4093,19 +4016,19 @@ void QObject::dumpObjectInfo() const objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data()); Q_D(const QObject); - QMutexLocker locker(signalSlotLock(this)); + QBasicMutexLocker locker(signalSlotLock(this)); // first, look for connections where this object is the sender qDebug(" SIGNALS OUT"); - if (d->connectionLists) { - for (int signal_index = 0; signal_index < d->connectionLists->count(); ++signal_index) { + QObjectPrivate::ConnectionData *cd = d->connections.load(); + if (cd && cd->signalVector.count()) { + for (int signal_index = 0; signal_index < cd->signalVector.count(); ++signal_index) { const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index); qDebug(" signal: %s", signal.methodSignature().constData()); // receivers - const QObjectPrivate::Connection *c = - d->connectionLists->at(signal_index).first; + const QObjectPrivate::Connection *c = cd->signalVector.at(signal_index).first; while (c) { if (!c->receiver) { qDebug(" <Disconnected receiver>"); @@ -4133,8 +4056,8 @@ void QObject::dumpObjectInfo() const // now look for connections where this object is the receiver qDebug(" SIGNALS IN"); - if (d->senders) { - for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) { + if (cd && cd->senders) { + for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) { QByteArray slotName = QByteArrayLiteral("<unknown>"); if (!s->isSlotObject) { const QMetaMethod slot = metaObject()->method(s->method()); @@ -4869,11 +4792,10 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s QOrderedMutexLocker locker(signalSlotLock(sender), signalSlotLock(receiver)); - if (type & Qt::UniqueConnection && slot) { - QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists; - if (connectionLists && connectionLists->count() > signal_index) { - const QObjectPrivate::Connection *c2 = - (*connectionLists)[signal_index].first; + if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.load()) { + QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.load(); + if (connections->signalVector.count() > signal_index) { + const QObjectPrivate::Connection *c2 = connections->signalVector.at(signal_index).first; while (c2) { if (c2->receiver == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) { @@ -4924,20 +4846,20 @@ bool QObject::disconnect(const QMetaObject::Connection &connection) if (!c || !c->receiver) return false; - QMutex *senderMutex = signalSlotLock(c->sender); - QMutex *receiverMutex = signalSlotLock(c->receiver); + QBasicMutex *senderMutex = signalSlotLock(c->sender); + QBasicMutex *receiverMutex = signalSlotLock(c->receiver); { QOrderedMutexLocker locker(senderMutex, receiverMutex); - QObjectConnectionListVector *connectionLists = QObjectPrivate::get(c->sender)->connectionLists; - Q_ASSERT(connectionLists); - connectionLists->dirty = true; + QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(c->sender)->connections.load(); + Q_ASSERT(connections); + connections->dirty = true; *c->prev = c->next; if (c->next) c->next->prev = c->prev; - c->receiver = 0; + c->receiver = nullptr; } // destroy the QSlotObject, if possible @@ -4949,7 +4871,7 @@ bool QObject::disconnect(const QMetaObject::Connection &connection) c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index)); - const_cast<QMetaObject::Connection &>(connection).d_ptr = 0; + const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr; c->deref(); // has been removed from the QMetaObject::Connection object return true; |