diff options
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 335 |
1 files changed, 189 insertions, 146 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 965857d408..5c1ae8aa43 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -58,6 +58,7 @@ #include <qdebug.h> #include <qpair.h> #include <qvarlengtharray.h> +#include <qscopeguard.h> #include <qset.h> #if QT_CONFIG(thread) #include <qsemaphore.h> @@ -81,7 +82,7 @@ Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_ void qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set) { - qt_signal_spy_callback_set.store(callback_set); + qt_signal_spy_callback_set.storeRelease(callback_set); } QDynamicMetaObjectData::~QDynamicMetaObjectData() @@ -218,10 +219,10 @@ QObjectPrivate::QObjectPrivate(int version) QObjectPrivate::~QObjectPrivate() { if (extraData && !extraData->runningTimers.isEmpty()) { - if (Q_LIKELY(threadData->thread == QThread::currentThread())) { + if (Q_LIKELY(threadData->thread.loadAcquire() == QThread::currentThread())) { // unregister pending timers if (threadData->hasEventDispatcher()) - threadData->eventDispatcher.load()->unregisterTimers(q_ptr); + threadData->eventDispatcher.loadRelaxed()->unregisterTimers(q_ptr); // release the timer ids back to the pool for (int i = 0; i < extraData->runningTimers.size(); ++i) @@ -267,17 +268,17 @@ bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const { Q_Q(const QObject); int signal_index = signalIndex(signal); - ConnectionData *cd = connections.load(); + ConnectionData *cd = connections.loadRelaxed(); if (signal_index < 0 || !cd) return false; QBasicMutexLocker locker(signalSlotLock(q)); if (signal_index < cd->signalVectorCount()) { - const QObjectPrivate::Connection *c = cd->signalVector.load()->at(signal_index).first.load(); + const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed(); while (c) { - if (c->receiver.load() == receiver) + if (c->receiver.loadRelaxed() == receiver) return true; - c = c->nextConnectionList.load(); + c = c->nextConnectionList.loadRelaxed(); } } return false; @@ -288,17 +289,17 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const { QObjectList returnValue; int signal_index = signalIndex(signal); - ConnectionData *cd = connections.load(); + ConnectionData *cd = connections.loadRelaxed(); if (signal_index < 0 || !cd) return returnValue; if (signal_index < cd->signalVectorCount()) { - const QObjectPrivate::Connection *c = cd->signalVector.load()->at(signal_index).first.load(); + const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed(); while (c) { - QObject *r = c->receiver.load(); + QObject *r = c->receiver.loadRelaxed(); if (r) returnValue << r; - c = c->nextConnectionList.load(); + c = c->nextConnectionList.loadRelaxed(); } } return returnValue; @@ -308,7 +309,7 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const QObjectList QObjectPrivate::senderList() const { QObjectList returnValue; - ConnectionData *cd = connections.load(); + ConnectionData *cd = connections.loadRelaxed(); if (cd) { QBasicMutexLocker locker(signalSlotLock(q_func())); for (Connection *c = cd->senders; c; c = c->next) @@ -331,24 +332,24 @@ void QObjectPrivate::addConnection(int signal, Connection *c) { Q_ASSERT(c->sender == q_ptr); ensureConnectionData(); - ConnectionData *cd = connections.load(); + ConnectionData *cd = connections.loadRelaxed(); cd->resizeSignalVector(signal + 1); ConnectionList &connectionList = cd->connectionsForSignal(signal); - if (connectionList.last.load()) { - Q_ASSERT(connectionList.last.load()->receiver.load()); - connectionList.last.load()->nextConnectionList.store(c); + if (connectionList.last.loadRelaxed()) { + Q_ASSERT(connectionList.last.loadRelaxed()->receiver.loadRelaxed()); + connectionList.last.loadRelaxed()->nextConnectionList.storeRelaxed(c); } else { - connectionList.first.store(c); + connectionList.first.storeRelaxed(c); } c->id = ++cd->currentConnectionId; - c->prevConnectionList = connectionList.last.load(); - connectionList.last.store(c); + c->prevConnectionList = connectionList.last.loadRelaxed(); + connectionList.last.storeRelaxed(c); - QObjectPrivate *rd = QObjectPrivate::get(c->receiver.load()); + QObjectPrivate *rd = QObjectPrivate::get(c->receiver.loadRelaxed()); rd->ensureConnectionData(); - c->prev = &(rd->connections.load()->senders); + c->prev = &(rd->connections.loadRelaxed()->senders); c->next = *c->prev; *c->prev = c; if (c->next) @@ -357,17 +358,17 @@ void QObjectPrivate::addConnection(int signal, Connection *c) void QObjectPrivate::ConnectionData::removeConnection(QObjectPrivate::Connection *c) { - Q_ASSERT(c->receiver.load()); - ConnectionList &connections = signalVector.load()->at(c->signal_index); - c->receiver.store(nullptr); - QThreadData *td = c->receiverThreadData.load(); + Q_ASSERT(c->receiver.loadRelaxed()); + ConnectionList &connections = signalVector.loadRelaxed()->at(c->signal_index); + c->receiver.storeRelaxed(nullptr); + QThreadData *td = c->receiverThreadData.loadRelaxed(); if (td) td->deref(); - c->receiverThreadData.store(nullptr); + c->receiverThreadData.storeRelaxed(nullptr); #ifndef QT_NO_DEBUG bool found = false; - for (Connection *cc = connections.first.load(); cc; cc = cc->nextConnectionList.load()) { + for (Connection *cc = connections.first.loadRelaxed(); cc; cc = cc->nextConnectionList.loadRelaxed()) { if (cc == c) { found = true; break; @@ -382,29 +383,29 @@ void QObjectPrivate::ConnectionData::removeConnection(QObjectPrivate::Connection c->next->prev = c->prev; c->prev = nullptr; - if (connections.first.load() == c) - connections.first.store(c->nextConnectionList.load()); - if (connections.last.load() == c) - connections.last.store(c->prevConnectionList); - Q_ASSERT(signalVector.load()->at(c->signal_index).first.load() != c); - Q_ASSERT(signalVector.load()->at(c->signal_index).last.load() != c); + if (connections.first.loadRelaxed() == c) + connections.first.storeRelaxed(c->nextConnectionList.loadRelaxed()); + if (connections.last.loadRelaxed() == c) + connections.last.storeRelaxed(c->prevConnectionList); + Q_ASSERT(signalVector.loadRelaxed()->at(c->signal_index).first.loadRelaxed() != c); + Q_ASSERT(signalVector.loadRelaxed()->at(c->signal_index).last.loadRelaxed() != c); // keep c->nextConnectionList intact, as it might still get accessed by activate - Connection *n = c->nextConnectionList.load(); + Connection *n = c->nextConnectionList.loadRelaxed(); if (n) n->prevConnectionList = c->prevConnectionList; if (c->prevConnectionList) - c->prevConnectionList->nextConnectionList.store(n); + c->prevConnectionList->nextConnectionList.storeRelaxed(n); c->prevConnectionList = nullptr; - Q_ASSERT(c != orphaned.load()); + Q_ASSERT(c != orphaned.loadRelaxed()); // add c to orphanedConnections - c->nextInOrphanList = orphaned.load(); - orphaned.store(c); + c->nextInOrphanList = orphaned.loadRelaxed(); + orphaned.storeRelaxed(c); #ifndef QT_NO_DEBUG found = false; - for (Connection *cc = connections.first.load(); cc; cc = cc->nextConnectionList.load()) { + for (Connection *cc = connections.first.loadRelaxed(); cc; cc = cc->nextConnectionList.loadRelaxed()) { if (cc == c) { found = true; break; @@ -420,14 +421,14 @@ void QObjectPrivate::ConnectionData::cleanOrphanedConnectionsImpl(QObject *sende ConnectionOrSignalVector *c = nullptr; { QBasicMutexLocker l(signalSlotLock(sender)); - if (ref > 1) + if (ref.loadAcquire() > 1) return; // Since ref == 1, no activate() is in process since we locked the mutex. That implies, // that nothing can reference the orphaned connection objects anymore and they can // be safely deleted - c = orphaned.load(); - orphaned.store(nullptr); + c = orphaned.loadRelaxed(); + orphaned.storeRelaxed(nullptr); } deleteOrphaned(c); } @@ -442,7 +443,7 @@ void QObjectPrivate::ConnectionData::deleteOrphaned(QObjectPrivate::ConnectionOr } else { QObjectPrivate::Connection *c = static_cast<Connection *>(o); next = c->nextInOrphanList; - Q_ASSERT(!c->receiver.load()); + Q_ASSERT(!c->receiver.loadRelaxed()); Q_ASSERT(!c->prev); c->freeSlotObject(); c->deref(); @@ -462,22 +463,22 @@ bool QObjectPrivate::isSignalConnected(uint signalIndex, bool checkDeclarative) if (checkDeclarative && isDeclarativeSignalConnected(signalIndex)) return true; - ConnectionData *cd = connections.load(); + ConnectionData *cd = connections.loadRelaxed(); if (!cd) return false; - SignalVector *signalVector = cd->signalVector.load(); + SignalVector *signalVector = cd->signalVector.loadRelaxed(); if (!signalVector) return false; - if (signalVector->at(-1).first.load()) + if (signalVector->at(-1).first.loadRelaxed()) return true; if (signalIndex < uint(cd->signalVectorCount())) { - const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.load(); + const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed(); while (c) { - if (c->receiver.load()) + if (c->receiver.loadRelaxed()) return true; - c = c->nextConnectionList.load(); + c = c->nextConnectionList.loadRelaxed(); } } return false; @@ -485,18 +486,18 @@ bool QObjectPrivate::isSignalConnected(uint signalIndex, bool checkDeclarative) bool QObjectPrivate::maybeSignalConnected(uint signalIndex) const { - ConnectionData *cd = connections.load(); + ConnectionData *cd = connections.loadRelaxed(); if (!cd) return false; - SignalVector *signalVector = cd->signalVector.load(); + SignalVector *signalVector = cd->signalVector.loadRelaxed(); if (!signalVector) return false; - if (signalVector->at(-1).first) + if (signalVector->at(-1).first.loadAcquire()) return true; if (signalIndex < uint(cd->signalVectorCount())) { - const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first; + const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire(); return c != nullptr; } return false; @@ -818,8 +819,8 @@ static bool check_parent_thread(QObject *parent, QThreadData *currentThreadData) { if (parent && parentThreadData != currentThreadData) { - QThread *parentThread = parentThreadData->thread; - QThread *currentThread = currentThreadData->thread; + QThread *parentThread = parentThreadData->thread.loadAcquire(); + QThread *currentThread = currentThreadData->thread.loadAcquire(); qWarning("QObject: Cannot create children for a parent that is in a different thread.\n" "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)", parent->metaObject()->className(), @@ -851,6 +852,8 @@ static bool check_parent_thread(QObject *parent, QObject::QObject(QObject *parent) : d_ptr(new QObjectPrivate) { + Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QObject to itself"); + Q_D(QObject); d_ptr->q_ptr = this; d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current(); @@ -879,6 +882,8 @@ QObject::QObject(QObject *parent) QObject::QObject(QObjectPrivate &dd, QObject *parent) : d_ptr(&dd) { + Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QObject to itself"); + Q_D(QObject); d_ptr->q_ptr = this; d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current(); @@ -939,15 +944,15 @@ QObject::~QObject() d->wasDeleted = true; d->blockSig = 0; // unblock signals so we always emit destroyed() - QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.load(); + QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed(); if (sharedRefcount) { - if (sharedRefcount->strongref.load() > 0) { + if (sharedRefcount->strongref.loadRelaxed() > 0) { qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash."); // but continue deleting, it's too late to stop anyway } // indicate to all QWeakPointers that this QObject has now been deleted - sharedRefcount->strongref.store(0); + sharedRefcount->strongref.storeRelaxed(0); if (!sharedRefcount->weakref.deref()) delete sharedRefcount; } @@ -966,7 +971,7 @@ QObject::~QObject() } } - QObjectPrivate::ConnectionData *cd = d->connections.load(); + QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed(); if (cd) { if (cd->currentSender) { cd->currentSender->receiverDeleted(); @@ -981,14 +986,14 @@ QObject::~QObject() for (int signal = -1; signal < receiverCount; ++signal) { QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal); - while (QObjectPrivate::Connection *c = connectionList.first.load()) { - Q_ASSERT(c->receiver); + while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) { + Q_ASSERT(c->receiver.loadAcquire()); - QBasicMutex *m = signalSlotLock(c->receiver.load()); + QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed()); bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); - if (c->receiver) { + if (c->receiver.loadAcquire()) { cd->removeConnection(c); - Q_ASSERT(connectionList.first.load() != c); + Q_ASSERT(connectionList.first.loadRelaxed() != c); } if (needToUnlock) m->unlock(); @@ -998,7 +1003,7 @@ QObject::~QObject() /* Disconnect all senders: */ while (QObjectPrivate::Connection *node = cd->senders) { - Q_ASSERT(node->receiver); + Q_ASSERT(node->receiver.loadAcquire()); 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 @@ -1014,7 +1019,7 @@ QObject::~QObject() continue; } - QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.load(); + QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed(); Q_ASSERT(senderData); QtPrivate::QSlotObjectBase *slotObj = nullptr; @@ -1036,11 +1041,11 @@ QObject::~QObject() // invalidate all connections on the object and make sure // activate() will skip them - cd->currentConnectionId.store(0); + cd->currentConnectionId.storeRelaxed(0); } if (cd && !cd->ref.deref()) delete cd; - d->connections.store(nullptr); + d->connections.storeRelaxed(nullptr); if (!d->children.isEmpty()) d->deleteChildren(); @@ -1060,7 +1065,7 @@ QObject::~QObject() QObjectPrivate::Connection::~Connection() { if (ownArgumentTypes) { - const int *v = argumentTypes.load(); + const int *v = argumentTypes.loadRelaxed(); if (v != &DIRECT_CONNECTION_ONLY) delete [] v; } @@ -1269,7 +1274,7 @@ bool QObject::event(QEvent *e) { QAbstractMetaCallEvent *mce = static_cast<QAbstractMetaCallEvent*>(e); - if (!d_func()->connections.load()) { + if (!d_func()->connections.loadRelaxed()) { QBasicMutexLocker locker(signalSlotLock(this)); d_func()->ensureConnectionData(); } @@ -1282,7 +1287,7 @@ bool QObject::event(QEvent *e) case QEvent::ThreadChange: { Q_D(QObject); QThreadData *threadData = d->threadData; - QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.load(); + QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed(); if (eventDispatcher) { QList<QAbstractEventDispatcher::TimerInfo> timers = eventDispatcher->registeredTimers(this); if (!timers.isEmpty()) { @@ -1448,7 +1453,7 @@ bool QObject::blockSignals(bool block) noexcept */ QThread *QObject::thread() const { - return d_func()->threadData->thread; + return d_func()->threadData->thread.loadAcquire(); } /*! @@ -1495,7 +1500,7 @@ void QObject::moveToThread(QThread *targetThread) { Q_D(QObject); - if (d->threadData->thread == targetThread) { + if (d->threadData->thread.loadAcquire() == targetThread) { // object is already in this thread return; } @@ -1511,13 +1516,13 @@ void QObject::moveToThread(QThread *targetThread) QThreadData *currentData = QThreadData::current(); QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr; - if (d->threadData->thread == 0 && currentData == targetData) { + if (d->threadData->thread.loadAcquire() == 0 && currentData == targetData) { // one exception to the rule: we allow moving objects with no thread affinity to the current thread currentData = d->threadData; } else if (d->threadData != currentData) { qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n" "Cannot move to target thread (%p)\n", - currentData->thread.load(), d->threadData->thread.load(), targetData ? targetData->thread.load() : nullptr); + currentData->thread.loadRelaxed(), d->threadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() : nullptr); #ifdef Q_OS_MAC qWarning("You might be loading two sets of Qt binaries into the same process. " @@ -1582,11 +1587,11 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData } if (eventsMoved > 0 && targetData->hasEventDispatcher()) { targetData->canWait = false; - targetData->eventDispatcher.load()->wakeUp(); + targetData->eventDispatcher.loadRelaxed()->wakeUp(); } // the current emitting thread shouldn't restore currentSender after calling moveToThread() - ConnectionData *cd = connections.load(); + ConnectionData *cd = connections.loadRelaxed(); if (cd) { if (cd->currentSender) { cd->currentSender->receiverDeleted(); @@ -1597,14 +1602,14 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData if (cd) { auto *c = cd->senders; while (c) { - QObject *r = c->receiver.load(); + QObject *r = c->receiver.loadRelaxed(); if (r) { Q_ASSERT(r == q); targetData->ref(); - QThreadData *old = c->receiverThreadData.load(); + QThreadData *old = c->receiverThreadData.loadRelaxed(); if (old) old->deref(); - c->receiverThreadData.store(targetData); + c->receiverThreadData.storeRelaxed(targetData); } c = c->next; } @@ -1627,7 +1632,7 @@ void QObjectPrivate::_q_reregisterTimers(void *pointer) { Q_Q(QObject); QList<QAbstractEventDispatcher::TimerInfo> *timerList = reinterpret_cast<QList<QAbstractEventDispatcher::TimerInfo> *>(pointer); - QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.load(); + QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed(); for (int i = 0; i < timerList->size(); ++i) { const QAbstractEventDispatcher::TimerInfo &ti = timerList->at(i); eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType, q); @@ -1693,7 +1698,7 @@ int QObject::startTimer(int interval, Qt::TimerType timerType) qWarning("QObject::startTimer: Timers cannot be started from another thread"); return 0; } - int timerId = d->threadData->eventDispatcher.load()->registerTimer(interval, timerType, this); + int timerId = d->threadData->eventDispatcher.loadRelaxed()->registerTimer(interval, timerType, this); if (!d->extraData) d->extraData = new QObjectPrivate::ExtraData; d->extraData->runningTimers.append(timerId); @@ -1768,7 +1773,7 @@ void QObject::killTimer(int id) } if (d->threadData->hasEventDispatcher()) - d->threadData->eventDispatcher.load()->unregisterTimer(id); + d->threadData->eventDispatcher.loadRelaxed()->unregisterTimer(id); d->extraData->runningTimers.remove(at); QAbstractEventDispatcherPrivate::releaseTimerId(id); @@ -2069,8 +2074,25 @@ void QObjectPrivate::deleteChildren() void QObjectPrivate::setParent_helper(QObject *o) { Q_Q(QObject); + Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself"); +#ifdef QT_DEBUG + const auto checkForParentChildLoops = qScopeGuard([&](){ + int depth = 0; + auto p = parent; + while (p) { + if (++depth == CheckForParentChildLoopsWarnDepth) { + qWarning("QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; " + "this is undefined behavior", + q, q->metaObject()->className(), qPrintable(q->objectName())); + } + p = p->parent(); + } + }); +#endif + if (o == parent) return; + if (parent) { QObjectPrivate *parentD = parent->d_func(); if (parentD->isDeletingChildren && wasDeleted @@ -2210,6 +2232,8 @@ void QObject::removeEventFilter(QObject *obj) */ /*! + \threadsafe + Schedules this object for deletion. The object will be deleted when control returns to the event @@ -2420,7 +2444,7 @@ QObject *QObject::sender() const Q_D(const QObject); QBasicMutexLocker locker(signalSlotLock(this)); - QObjectPrivate::ConnectionData *cd = d->connections.load(); + QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed(); if (!cd || !cd->currentSender) return nullptr; @@ -2462,7 +2486,7 @@ int QObject::senderSignalIndex() const Q_D(const QObject); QBasicMutexLocker locker(signalSlotLock(this)); - QObjectPrivate::ConnectionData *cd = d->connections.load(); + QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed(); if (!cd || !cd->currentSender) return -1; @@ -2525,13 +2549,13 @@ int QObject::receivers(const char *signal) const signal_index); } - QObjectPrivate::ConnectionData *cd = d->connections.load(); + QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed(); QBasicMutexLocker locker(signalSlotLock(this)); if (cd && signal_index < cd->signalVectorCount()) { - const QObjectPrivate::Connection *c = cd->signalVector.load()->at(signal_index).first.load(); + const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed(); while (c) { - receivers += c->receiver.load() ? 1 : 0; - c = c->nextConnectionList.load(); + receivers += c->receiver.loadRelaxed() ? 1 : 0; + c = c->nextConnectionList.loadRelaxed(); } } } @@ -3340,17 +3364,17 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, QOrderedMutexLocker locker(signalSlotLock(sender), signalSlotLock(receiver)); - QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.load(); + QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed(); if (type & Qt::UniqueConnection && scd) { if (scd->signalVectorCount() > signal_index) { - const QObjectPrivate::Connection *c2 = scd->signalVector.load()->at(signal_index).first.load(); + const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed(); int method_index_absolute = method_index + method_offset; while (c2) { - if (!c2->isSlotObject && c2->receiver.load() == receiver && c2->method() == method_index_absolute) + if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute) return nullptr; - c2 = c2->nextConnectionList.load(); + c2 = c2->nextConnectionList.loadRelaxed(); } } type &= Qt::UniqueConnection - 1; @@ -3359,15 +3383,15 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection); c->sender = s; c->signal_index = signal_index; - c->receiver.store(r); + c->receiver.storeRelaxed(r); QThreadData *td = r->d_func()->threadData; td->ref(); - c->receiverThreadData.store(td); + c->receiverThreadData.storeRelaxed(td); c->method_relative = method_index; c->method_offset = method_offset; c->connectionType = type; c->isSlotObject = false; - c->argumentTypes.store(types); + c->argumentTypes.storeRelaxed(types); c->callFunction = callFunction; QObjectPrivate::get(s)->addConnection(signal_index, c.data()); @@ -3420,9 +3444,9 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::ConnectionData *connec bool success = false; auto &connectionList = connections->connectionsForSignal(signalIndex); - auto *c = connectionList.first.load(); + auto *c = connectionList.first.loadRelaxed(); while (c) { - QObject *r = c->receiver.load(); + QObject *r = c->receiver.loadRelaxed(); if (r && (receiver == nullptr || (r == receiver && (method_index < 0 || (!c->isSlotObject && c->method() == method_index)) && (slot == nullptr || (c->isSlotObject && c->slotObj->compare(slot)))))) { @@ -3433,7 +3457,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::ConnectionData *connec // need to relock this receiver and sender in the correct order needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex); } - if (c->receiver.load()) + if (c->receiver.loadRelaxed()) connections->removeConnection(c); if (needToUnlock) @@ -3444,7 +3468,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::ConnectionData *connec if (disconnectType == DisconnectOne) return success; } - c = c->nextConnectionList.load(); + c = c->nextConnectionList.loadRelaxed(); } return success; } @@ -3466,7 +3490,7 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, QBasicMutex *senderMutex = signalSlotLock(sender); QBasicMutexLocker locker(senderMutex); - QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.load(); + QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed(); if (!scd) return false; @@ -3608,7 +3632,7 @@ void QMetaObject::connectSlotsByName(QObject *o) */ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv) { - const int *argumentTypes = c->argumentTypes.load(); + const int *argumentTypes = c->argumentTypes.loadRelaxed(); if (!argumentTypes) { QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal); argumentTypes = queuedConnectionTypes(m.parameterTypes()); @@ -3617,7 +3641,7 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect if (!c->argumentTypes.testAndSetOrdered(0, argumentTypes)) { if (argumentTypes != &DIRECT_CONNECTION_ONLY) delete [] argumentTypes; - argumentTypes = c->argumentTypes.load(); + argumentTypes = c->argumentTypes.loadRelaxed(); } } if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate @@ -3640,8 +3664,8 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect args[n] = QMetaType::create(types[n], argv[n]); } - QBasicMutexLocker locker(signalSlotLock(c->receiver.load())); - if (!c->receiver.load()) { + QBasicMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed())); + if (!c->receiver.loadRelaxed()) { // the connection has been disconnected before we got the lock locker.unlock(); for (int n = 1; n < nargs; ++n) @@ -3654,7 +3678,7 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect QMetaCallEvent *ev = c->isSlotObject ? new QMetaCallEvent(c->slotObj, sender, signal, nargs, types, args) : new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs, types, args); - QCoreApplication::postEvent(c->receiver.load(), ev); + QCoreApplication::postEvent(c->receiver.loadRelaxed(), ev); } template <bool callbacks_enabled> @@ -3674,7 +3698,7 @@ void doActivate(QObject *sender, int signal_index, void **argv) signal_index, argv); } - const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.load() : nullptr; + const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr; void *empty_argv[] = { nullptr }; if (!argv) @@ -3694,9 +3718,9 @@ void doActivate(QObject *sender, int signal_index, void **argv) bool senderDeleted = false; { - Q_ASSERT(sp->connections); - QObjectPrivate::ConnectionDataPointer connections(sp->connections.load()); - QObjectPrivate::SignalVector *signalVector = connections->signalVector.load(); + 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()) @@ -3705,32 +3729,32 @@ void doActivate(QObject *sender, int signal_index, void **argv) list = &signalVector->at(-1); Qt::HANDLE currentThreadId = QThread::currentThreadId(); - bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData->threadId.load(); + bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData->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.load(); + uint highestConnectionId = connections->currentConnectionId.loadRelaxed(); do { - QObjectPrivate::Connection *c = list->first.load(); + QObjectPrivate::Connection *c = list->first.loadRelaxed(); if (!c) continue; do { - QObject * const receiver = c->receiver.load(); + QObject * const receiver = c->receiver.loadRelaxed(); if (!receiver) continue; - QThreadData *td = c->receiverThreadData.load(); + QThreadData *td = c->receiverThreadData.loadRelaxed(); if (!td) continue; bool receiverInSameThread; if (inSenderThread) { - receiverInSameThread = currentThreadId == td->threadId.load(); + 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.load(); + receiverInSameThread = currentThreadId == td->threadId.loadRelaxed(); } @@ -3751,7 +3775,7 @@ void doActivate(QObject *sender, int signal_index, void **argv) QSemaphore semaphore; { QBasicMutexLocker locker(signalSlotLock(sender)); - if (!c->receiver) + if (!c->receiver.loadAcquire()) continue; QMetaCallEvent *ev = c->isSlotObject ? new QMetaCallEvent(c->slotObj, sender, signal_index, 0, 0, argv, &semaphore) : @@ -3803,17 +3827,17 @@ void doActivate(QObject *sender, int signal_index, void **argv) if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr) signal_spy_set->slot_end_callback(receiver, method); } - } while ((c = c->nextConnectionList.load()) != nullptr && c->id <= highestConnectionId); + } 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.load() == 0) + if (connections->currentConnectionId.loadRelaxed() == 0) senderDeleted = true; } if (!senderDeleted) - sp->connections.load()->cleanOrphanedConnections(sender); + sp->connections.loadRelaxed()->cleanOrphanedConnections(sender); if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr) signal_spy_set->signal_end_callback(sender, signal_index); @@ -3827,7 +3851,7 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign { int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m); - if (Q_UNLIKELY(qt_signal_spy_callback_set.load())) + if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed())) doActivate<true>(sender, signal_index, argv); else doActivate<false>(sender, signal_index, argv); @@ -3840,7 +3864,7 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i { int signal_index = signalOffset + local_signal_index; - if (Q_UNLIKELY(qt_signal_spy_callback_set.load())) + if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed())) doActivate<true>(sender, signal_index, argv); else doActivate<false>(sender, signal_index, argv); @@ -4109,11 +4133,11 @@ void QObject::dumpObjectInfo() const // first, look for connections where this object is the sender qDebug(" SIGNALS OUT"); - QObjectPrivate::ConnectionData *cd = d->connections.load(); + QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed(); if (cd && cd->signalVectorCount()) { - QObjectPrivate::SignalVector *signalVector = cd->signalVector.load(); + QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed(); for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) { - const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.load(); + const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed(); if (!c) continue; const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index); @@ -4121,23 +4145,23 @@ void QObject::dumpObjectInfo() const // receivers while (c) { - if (!c->receiver.load()) { + if (!c->receiver.loadRelaxed()) { qDebug(" <Disconnected receiver>"); - c = c->nextConnectionList.load(); + c = c->nextConnectionList.loadRelaxed(); continue; } if (c->isSlotObject) { qDebug(" <functor or function pointer>"); - c = c->nextConnectionList.load(); + c = c->nextConnectionList.loadRelaxed(); continue; } - const QMetaObject *receiverMetaObject = c->receiver.load()->metaObject(); + const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject(); const QMetaMethod method = receiverMetaObject->method(c->method()); qDebug(" --> %s::%s %s", receiverMetaObject->className(), - c->receiver.load()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.load()->objectName()), + c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()), method.methodSignature().constData()); - c = c->nextConnectionList.load(); + c = c->nextConnectionList.loadRelaxed(); } } } else { @@ -4165,13 +4189,14 @@ void QObject::dumpObjectInfo() const } #ifndef QT_NO_USERDATA +static QBasicAtomicInteger<uint> user_data_registration = Q_BASIC_ATOMIC_INITIALIZER(0); + /*! \internal */ uint QObject::registerUserData() { - static int user_data_registration = 0; - return user_data_registration++; + return user_data_registration.fetchAndAddRelaxed(1); } /*! @@ -4504,6 +4529,24 @@ QDebug operator<<(QDebug dbg, const QObject *o) Q_NAMESPACE makes an external variable, \c{staticMetaObject}, available. \c{staticMetaObject} is of type QMetaObject and provides access to the enums declared with Q_ENUM_NS/Q_FLAG_NS. + + \sa Q_NAMESPACE_EXPORT +*/ + +/*! + \macro Q_NAMESPACE_EXPORT(EXPORT_MACRO) + \relates QObject + \since 5.14 + + The Q_NAMESPACE_EXPORT macro can be used to add QMetaObject capabilities + to a namespace. + + It works exactly like the Q_NAMESPACE macro. However, the external + \c{staticMetaObject} variable that gets defined in the namespace + is declared with the supplied \c{EXPORT_MACRO} qualifier. This is + useful f.i. if the object needs to be exported from a dynamic library. + + \sa Q_NAMESPACE, {Creating Shared Libraries} */ /*! @@ -4888,17 +4931,17 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s QOrderedMutexLocker locker(signalSlotLock(sender), signalSlotLock(receiver)); - if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.load()) { - QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.load(); + if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.loadRelaxed()) { + QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed(); if (connections->signalVectorCount() > signal_index) { - const QObjectPrivate::Connection *c2 = connections->signalVector.load()->at(signal_index).first.load(); + const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed(); while (c2) { - if (c2->receiver.load() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) { + if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) { slotObj->destroyIfLastRef(); return QMetaObject::Connection(); } - c2 = c2->nextConnectionList.load(); + c2 = c2->nextConnectionList.loadRelaxed(); } } type = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection); @@ -4909,13 +4952,13 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s c->signal_index = signal_index; QThreadData *td = r->d_func()->threadData; td->ref(); - c->receiverThreadData.store(td); - c->receiver.store(r); + c->receiverThreadData.storeRelaxed(td); + c->receiver.storeRelaxed(r); c->slotObj = slotObj; c->connectionType = type; c->isSlotObject = true; if (types) { - c->argumentTypes.store(types); + c->argumentTypes.storeRelaxed(types); c->ownArgumentTypes = false; } @@ -4944,7 +4987,7 @@ bool QObject::disconnect(const QMetaObject::Connection &connection) if (!c) return false; - QObject *receiver = c->receiver.load(); + QObject *receiver = c->receiver.loadRelaxed(); if (!receiver) return false; @@ -4956,11 +4999,11 @@ bool QObject::disconnect(const QMetaObject::Connection &connection) QOrderedMutexLocker locker(senderMutex, receiverMutex); // load receiver once again and recheck to ensure nobody else has removed the connection in the meantime - receiver = c->receiver.load(); + receiver = c->receiver.loadRelaxed(); if (!receiver) return false; - connections = QObjectPrivate::get(c->sender)->connections.load(); + connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed(); Q_ASSERT(connections); connections->removeConnection(c); } @@ -5152,7 +5195,7 @@ bool QMetaObject::Connection::isConnected_helper() const Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(d_ptr); - return c->receiver.load(); + return c->receiver.loadRelaxed(); } |