summaryrefslogtreecommitdiffstats
path: root/src/kernel/qobject.cpp
diff options
context:
space:
mode:
authorTimothy Pearson <[email protected]>2013-05-14 19:34:10 -0500
committerTimothy Pearson <[email protected]>2013-05-14 19:34:10 -0500
commit4eba9b823832a5bab1acffeabc245b06fe113d75 (patch)
tree9ec81ead726a66066c6450c805beb8e233391a65 /src/kernel/qobject.cpp
parentbe8413249bb8a6d8dc2cfc693d9c1037284fd251 (diff)
downloadqt3-4eba9b823832a5bab1acffeabc245b06fe113d75.tar.gz
qt3-4eba9b823832a5bab1acffeabc245b06fe113d75.zip
Fix a number of threading data races
Add proper thread termination handler This partially resolves Bug 1508
Diffstat (limited to 'src/kernel/qobject.cpp')
-rw-r--r--src/kernel/qobject.cpp199
1 files changed, 177 insertions, 22 deletions
diff --git a/src/kernel/qobject.cpp b/src/kernel/qobject.cpp
index a3f4f18..9e5ac8e 100644
--- a/src/kernel/qobject.cpp
+++ b/src/kernel/qobject.cpp
@@ -73,6 +73,8 @@ public:
}
#endif
QThread* ownThread;
+ QMutex* senderObjectListMutex;
+ QMutex* childObjectListMutex;
bool disableThreadPostedEvents;
};
@@ -83,6 +85,10 @@ void QObject::moveToThread_helper(QThread *targetThread)
QEvent e(QEvent::ThreadChange);
QApplication::sendEvent(this, &e);
+#ifdef QT_THREAD_SUPPORT
+ QMutexLocker locker( d->childObjectListMutex );
+#endif // QT_THREAD_SUPPORT
+
if (childObjects) {
QObject *child;
QObjectListIt it(*childObjects);
@@ -97,12 +103,16 @@ void QObject::setThreadObject_helper(QThread *targetThread)
{
d->ownThread = targetThread;
+#ifdef QT_THREAD_SUPPORT
+ QMutexLocker locker( d->childObjectListMutex );
+#endif // QT_THREAD_SUPPORT
+
if (childObjects) {
QObject *child;
QObjectListIt it(*childObjects);
while ( (child=it.current()) ) {
++it;
- child->moveToThread_helper(targetThread);
+ child->setThreadObject_helper(targetThread);
}
}
}
@@ -123,7 +133,9 @@ void QObject::setThreadObject_helper(QThread *targetThread)
*/
void QObject::moveToThread(QThread *targetThread)
{
+#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( QApplication::qt_mutex );
+#endif // QT_THREAD_SUPPORT
if (parentObj) {
#if defined(QT_DEBUG)
@@ -179,11 +191,23 @@ void QObject::disableThreadPostedEvents(bool disable) {
class QSenderObjectList : public QObjectList, public QShared
{
-public:
- QSenderObjectList() : currentSender( 0 ) { }
- QObject *currentSender;
+ public:
+ QSenderObjectList();
+ ~QSenderObjectList();
+
+ public:
+ QObject *currentSender;
+ QMutex *listMutex;
};
+QSenderObjectList::QSenderObjectList() : currentSender( 0 ) {
+ listMutex = new QMutex( TRUE );
+}
+
+QSenderObjectList::~QSenderObjectList() {
+ delete listMutex;
+}
+
class Q_EXPORT QMetaCallEvent : public QEvent
{
public:
@@ -369,8 +393,9 @@ bool qKillTimer( QObject *obj );
static void removeObjFromList( QObjectList *objList, const QObject *obj,
bool single=FALSE )
{
- if ( !objList )
+ if ( !objList ) {
return;
+ }
int index = objList->findRef( obj );
while ( index >= 0 ) {
objList->remove();
@@ -585,20 +610,25 @@ QObject::QObject( QObject *parent, const char *name )
postedEvents( 0 ), // no events posted
d( 0 )
{
- if ( !metaObj ) // will create object dict
+ if ( !d ) {
+ d = new QObjectPrivate(0);
+ }
+
+ d->ownThread = QThread::currentThreadObject();
+ d->senderObjectListMutex = new QMutex( TRUE );
+ d->childObjectListMutex = new QMutex( TRUE );
+
+ if ( !metaObj ) { // will create object dict
(void) staticMetaObject();
+ }
if ( parent ) { // add object to parent
parent->insertChild( this );
- } else {
+ }
+ else {
insert_tree( this );
isTree = TRUE;
}
-
- if ( !d )
- d = new QObjectPrivate(0);
-
- d->ownThread = QThread::currentThreadObject();
}
@@ -630,10 +660,15 @@ QObject::~QObject()
#endif
return;
}
+ if (qApp) {
+ QEvent destroyEvent(QEvent::Destroy);
+ qApp->notify(this, &destroyEvent);
+ }
wasDeleted = 1;
blockSig = 0; // unblock signals to keep QGuardedPtr happy
emit destroyed( this );
emit destroyed();
+
if ( objname ) {
delete [] (char*)objname;
}
@@ -669,8 +704,9 @@ QObject::~QObject()
QConnectionListIt cit(*clist);
while( (c=cit.current()) ) { // for each connected slot...
++cit;
- if ( (obj=c->object()) )
+ if ( (obj=c->object()) ) {
removeObjFromList( obj->senderObjects, this );
+ }
}
}
delete connections;
@@ -691,6 +727,11 @@ QObject::~QObject()
delete childObjects;
}
+#ifdef QT_THREAD_SUPPORT
+ delete d->childObjectListMutex;
+ delete d->senderObjectListMutex;
+#endif // QT_THREAD_SUPPORT
+
delete d;
}
@@ -985,11 +1026,17 @@ bool QObject::event( QEvent *e )
QSenderObjectList* sol;
QObject* oldSender = 0;
sol = senderObjects;
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
if ( sol ) {
oldSender = sol->currentSender;
sol->ref();
sol->currentSender = metaEvent->sender();
}
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
QUObject *o = metaEvent->data();
if (metaEvent->type() == QMetaCallEvent::MetaCallEmit) {
qt_emit( metaEvent->id(), o );
@@ -997,12 +1044,20 @@ bool QObject::event( QEvent *e )
if (metaEvent->type() == QMetaCallEvent::MetaCallInvoke) {
qt_invoke( metaEvent->id(), o );
}
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
if (sol ) {
sol->currentSender = oldSender;
if ( sol->deref() ) {
+ sol->listMutex->unlock();
delete sol;
+ sol = NULL;
}
}
+#ifdef QT_THREAD_SUPPORT
+ if (sol) sol->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
}
else {
qWarning("QObject: Ignoring metacall event from non-owning thread");
@@ -1509,6 +1564,10 @@ QConnectionList *QObject::receivers( int signal ) const
void QObject::insertChild( QObject *obj )
{
+#ifdef QT_THREAD_SUPPORT
+ QMutexLocker locker( d->childObjectListMutex );
+#endif // QT_THREAD_SUPPORT
+
if ( obj->isTree ) {
remove_tree( obj );
obj->isTree = FALSE;
@@ -1551,6 +1610,10 @@ void QObject::insertChild( QObject *obj )
void QObject::removeChild( QObject *obj )
{
+#ifdef QT_THREAD_SUPPORT
+ QMutexLocker locker( d->childObjectListMutex );
+#endif // QT_THREAD_SUPPORT
+
if ( childObjects && childObjects->removeRef(obj) ) {
obj->parentObj = 0;
if ( !obj->wasDeleted ) {
@@ -2135,9 +2198,25 @@ void QObject::connectInternal( const QObject *sender, int signal_index, const QO
QConnection *c = new QConnection( r, member_index, rm ? rm->name : "qt_invoke", membcode );
Q_CHECK_PTR( c );
clist->append( c );
- if ( !r->senderObjects ) // create list of senders
+ if ( !r->senderObjects ) { // create list of senders
+#ifdef QT_THREAD_SUPPORT
+ r->d->senderObjectListMutex->lock();
+#endif // QT_THREAD_SUPPORT
r->senderObjects = new QSenderObjectList;
+#ifdef QT_THREAD_SUPPORT
+ r->senderObjects->listMutex->lock();
+ r->d->senderObjectListMutex->unlock();
+#endif // QT_THREAD_SUPPORT
+ }
+ else {
+#ifdef QT_THREAD_SUPPORT
+ r->senderObjects->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
+ }
r->senderObjects->append( s ); // add sender to list
+#ifdef QT_THREAD_SUPPORT
+ r->senderObjects->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
}
@@ -2343,13 +2422,25 @@ bool QObject::disconnectInternal( const QObject *sender, int signal_index,
c = clist->first();
while ( c ) { // for all receivers...
if ( r == 0 ) { // remove all receivers
+#ifdef QT_THREAD_SUPPORT
+ if (c->object()->senderObjects) c->object()->senderObjects->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
removeObjFromList( c->object()->senderObjects, s );
+#ifdef QT_THREAD_SUPPORT
+ if (c->object()->senderObjects) c->object()->senderObjects->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
success = TRUE;
c = clist->next();
} else if ( r == c->object() &&
( (member_index == -1) ||
((member_index == c->member()) && (c->memberType() == membcode)) ) ) {
+#ifdef QT_THREAD_SUPPORT
+ if (c->object()->senderObjects) c->object()->senderObjects->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
removeObjFromList( c->object()->senderObjects, s, TRUE );
+#ifdef QT_THREAD_SUPPORT
+ if (c->object()->senderObjects) c->object()->senderObjects->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
success = TRUE;
clist->remove();
c = clist->current();
@@ -2368,13 +2459,25 @@ bool QObject::disconnectInternal( const QObject *sender, int signal_index,
c = clist->first();
while ( c ) { // for all receivers...
if ( r == 0 ) { // remove all receivers
+#ifdef QT_THREAD_SUPPORT
+ if (c->object()->senderObjects) c->object()->senderObjects->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
removeObjFromList( c->object()->senderObjects, s, TRUE );
+#ifdef QT_THREAD_SUPPORT
+ if (c->object()->senderObjects) c->object()->senderObjects->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
success = TRUE;
c = clist->next();
} else if ( r == c->object() &&
( (member_index == -1) ||
((member_index == c->member()) && (c->memberType() == membcode)) ) ) {
+#ifdef QT_THREAD_SUPPORT
+ if (c->object()->senderObjects) c->object()->senderObjects->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
removeObjFromList( c->object()->senderObjects, s, TRUE );
+#ifdef QT_THREAD_SUPPORT
+ if (c->object()->senderObjects) c->object()->senderObjects->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
success = TRUE;
clist->remove();
c = clist->current();
@@ -2382,8 +2485,9 @@ bool QObject::disconnectInternal( const QObject *sender, int signal_index,
c = clist->next();
}
}
- if ( r == 0 ) // disconnect all receivers
+ if ( r == 0 ) { // disconnect all receivers
s->connections->insert( signal_index, 0 );
+ }
}
return success;
}
@@ -2578,11 +2682,13 @@ void QObject::activate_signal( int signal )
}
#endif
- if ( !connections || signalsBlocked() || signal < 0 )
+ if ( !connections || signalsBlocked() || signal < 0 ) {
return;
+ }
QConnectionList *clist = connections->at( signal );
- if ( !clist )
+ if ( !clist ) {
return;
+ }
QUObject o[1];
o[0].isLastObject = true;
activate_signal( clist, o );
@@ -2592,12 +2698,14 @@ void QObject::activate_signal( int signal )
void QObject::activate_signal( QConnectionList *clist, QUObject *o )
{
- if ( !clist )
+ if ( !clist ) {
return;
+ }
#ifndef QT_NO_PRELIMINARY_SIGNAL_SPY
- if ( qt_preliminary_signal_spy )
+ if ( qt_preliminary_signal_spy ) {
qt_spy_signal( this, connections->findRef( clist), o );
+ }
#endif
const QThread *currentThread = QThread::currentThreadObject();
@@ -2610,6 +2718,9 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
c = clist->first();
object = c->object();
sol = object->senderObjects;
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
if ( sol ) {
oldSender = sol->currentSender;
sol->ref();
@@ -2617,7 +2728,13 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
}
if ( c->memberType() == QSIGNAL_CODE ) {
if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) {
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
object->qt_emit( c->member(), o );
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
}
else {
if (object->d->ownThread && !object->d->ownThread->finished()) {
@@ -2627,7 +2744,13 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
}
else {
if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) {
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
object->qt_invoke( c->member(), o );
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
}
else {
if (object->d->ownThread && !object->d->ownThread->finished()) {
@@ -2637,9 +2760,15 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
}
if ( sol ) {
sol->currentSender = oldSender;
- if ( sol->deref() )
+ if ( sol->deref() ) {
+ sol->listMutex->unlock();
delete sol;
+ sol = NULL;
+ }
}
+#ifdef QT_THREAD_SUPPORT
+ if (sol) sol->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
} else {
QConnection *cd = 0;
QConnectionListIt it(*clist);
@@ -2650,6 +2779,9 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
cd = c;
object = c->object();
sol = object->senderObjects;
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
if ( sol ) {
oldSender = sol->currentSender;
sol->ref();
@@ -2657,7 +2789,13 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
}
if ( c->memberType() == QSIGNAL_CODE ) {
if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) {
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
object->qt_emit( c->member(), o );
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
}
else {
if (object->d->ownThread && !object->d->ownThread->finished()) {
@@ -2667,7 +2805,13 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
}
else {
if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) {
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
object->qt_invoke( c->member(), o );
+#ifdef QT_THREAD_SUPPORT
+ sol->listMutex->lock();
+#endif // QT_THREAD_SUPPORT
}
else {
if (object->d->ownThread && !object->d->ownThread->finished()) {
@@ -2677,9 +2821,15 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
}
if (sol ) {
sol->currentSender = oldSender;
- if ( sol->deref() )
+ if ( sol->deref() ) {
+ sol->listMutex->unlock();
delete sol;
+ sol = NULL;
+ }
}
+#ifdef QT_THREAD_SUPPORT
+ if (sol) sol->listMutex->unlock();
+#endif // QT_THREAD_SUPPORT
}
}
}
@@ -2818,6 +2968,10 @@ void QObject::dumpObjectTree()
void QObject::dumpObjectInfo()
{
+#ifdef QT_THREAD_SUPPORT
+ QMutexLocker locker( d->senderObjectListMutex );
+#endif // QT_THREAD_SUPPORT
+
#if defined(QT_DEBUG)
qDebug( "OBJECT %s::%s", className(), name( "unnamed" ) );
int n = 0;
@@ -2852,8 +3006,9 @@ void QObject::dumpObjectInfo()
sender = senderObjects->next();
}
}
- if ( n == 0 )
+ if ( n == 0 ) {
qDebug( "\t<None>" );
+ }
#endif
}