diff options
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 55 |
1 files changed, 36 insertions, 19 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 72ce941b6e..29c5a3dd24 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -177,6 +178,7 @@ private: void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = 0; +void (*QAbstractDeclarativeData::destroyed_qml1)(QAbstractDeclarativeData *, QObject *) = 0; void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0; void (*QAbstractDeclarativeData::signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **) = 0; int (*QAbstractDeclarativeData::receivers)(QAbstractDeclarativeData *, const QObject *, int) = 0; @@ -639,7 +641,7 @@ void QMetaCallEvent::placeMetaCall(QObject *object) \li When a QObject is moved to another thread, all its children will be automatically moved too. \li moveToThread() will fail if the QObject has a parent. - \li If \l{QObject}s are created within QThread::run(), they cannot + \li If QObjects are created within QThread::run(), they cannot become children of the QThread object because the QThread does not live in the thread that calls QThread::run(). \endlist @@ -878,8 +880,12 @@ QObject::~QObject() } } - if (d->declarativeData) - QAbstractDeclarativeData::destroyed(d->declarativeData, this); + if (d->declarativeData) { + if (QAbstractDeclarativeData::destroyed) + QAbstractDeclarativeData::destroyed(d->declarativeData, this); + if (QAbstractDeclarativeData::destroyed_qml1) + QAbstractDeclarativeData::destroyed_qml1(d->declarativeData, this); + } // set ref to zero to indicate that this object has been deleted if (d->currentSender != 0) @@ -920,9 +926,9 @@ QObject::~QObject() // The destroy operation must happen outside the lock if (c->isSlotObject) { + c->isSlotObject = false; locker.unlock(); c->slotObj->destroyIfLastRef(); - c->isSlotObject = false; locker.relock(); } c->deref(); @@ -937,15 +943,29 @@ QObject::~QObject() d->connectionLists = 0; } - // disconnect all senders + /* Disconnect all senders: + * This loop basically just does + * for (node = d->senders; node; node = node->next) { ... } + * + * We need to temporarily unlock the receiver mutex to destroy the functors or to lock the + * sender's mutex. And when the mutex is released, node->next might be destroyed by another + * 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; while (node) { 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); node->prev = &node; bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); //the node has maybe been removed while the mutex was unlocked in relock? if (!node || node->sender != sender) { + // We hold the wrong mutex + Q_ASSERT(needToUnlock); m->unlock(); continue; } @@ -954,8 +974,6 @@ QObject::~QObject() if (senderLists) senderLists->dirty = true; - int signal_index = node->signal_index; - QtPrivate::QSlotObjectBase *slotObj = Q_NULLPTR; if (node->isSlotObject) { slotObj = node->slotObj; @@ -967,12 +985,12 @@ QObject::~QObject() m->unlock(); if (slotObj) { + if (node) + node->prev = &node; locker.unlock(); slotObj->destroyIfLastRef(); locker.relock(); } - - sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), signal_index)); } } @@ -1557,12 +1575,12 @@ int QObject::startTimer(int interval, Qt::TimerType timerType) Q_D(QObject); if (interval < 0) { - qWarning("QObject::startTimer: QTimer cannot have a negative interval"); + qWarning("QObject::startTimer: Timers cannot have negative intervals"); return 0; } if (!d->threadData->eventDispatcher.load()) { - qWarning("QObject::startTimer: QTimer can only be used with threads started with QThread"); + qWarning("QObject::startTimer: Timers can only be used with threads started with QThread"); return 0; } int timerId = d->threadData->eventDispatcher.load()->registerTimer(interval, timerType, this); @@ -1931,7 +1949,7 @@ void QObjectPrivate::setParent_helper(QObject *o) } } } - if (!isDeletingChildren && declarativeData) + if (!isDeletingChildren && declarativeData && QAbstractDeclarativeData::parentChanged) QAbstractDeclarativeData::parentChanged(declarativeData, q, o); } @@ -3236,7 +3254,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, && (slot == 0 || (c->isSlotObject && c->slotObj->compare(slot)))))) { bool needToUnlock = false; QMutex *receiverMutex = 0; - if (!receiver) { + if (c->receiver) { receiverMutex = signalSlotLock(c->receiver); // need to relock this receiver and sender in the correct order needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex); @@ -3253,9 +3271,9 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, c->receiver = 0; if (c->isSlotObject) { + c->isSlotObject = false; senderMutex->unlock(); c->slotObj->destroyIfLastRef(); - c->isSlotObject = false; senderMutex->lock(); } @@ -3284,8 +3302,7 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, QObject *s = const_cast<QObject *>(sender); QMutex *senderMutex = signalSlotLock(sender); - QMutex *receiverMutex = receiver ? signalSlotLock(receiver) : 0; - QOrderedMutexLocker locker(senderMutex, receiverMutex); + QMutexLocker locker(senderMutex); QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists; if (!connectionLists) @@ -4213,7 +4230,7 @@ QDebug operator<<(QDebug dbg, const QObject *o) { \macro Q_INVOKABLE \relates QObject - Apply this macro to definitions of member functions to allow them to + Apply this macro to declarations of member functions to allow them to be invoked via the meta-object system. The macro is written before the return type, as shown in the following example: @@ -4230,7 +4247,7 @@ QDebug operator<<(QDebug dbg, const QObject *o) { \macro Q_REVISION \relates QObject - Apply this macro to definitions of member functions to tag them with a + Apply this macro to declarations of member functions to tag them with a revision number in the meta-object system. The macro is written before the return type, as shown in the following example: @@ -4695,7 +4712,7 @@ bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void ** It can be used to disconnect that connection, or check if the connection was successful - \sa QObject::disconnect + \sa QObject::disconnect() */ /*! |