summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r--src/corelib/kernel/qobject.cpp55
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()
*/
/*!