diff options
author | Timothy Pearson <[email protected]> | 2013-05-14 19:34:10 -0500 |
---|---|---|
committer | Timothy Pearson <[email protected]> | 2013-05-14 19:34:10 -0500 |
commit | 4eba9b823832a5bab1acffeabc245b06fe113d75 (patch) | |
tree | 9ec81ead726a66066c6450c805beb8e233391a65 /src/kernel/qobject.cpp | |
parent | be8413249bb8a6d8dc2cfc693d9c1037284fd251 (diff) | |
download | qt3-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.cpp | 199 |
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 } |