diff options
author | Alexander Golubev <fatzer2@gmail.com> | 2024-03-16 08:14:54 +0300 |
---|---|---|
committer | Alexander Golubev <fatzer2@gmail.com> | 2024-03-16 08:14:54 +0300 |
commit | 6250349b0b0a48a23b6cd847e70330e90c812bcc (patch) | |
tree | e376dcf0d886faafcf95eb5454c3ecd7ca2943b1 | |
parent | 24eb408f6a99f2b43ec6980e903a5d3525cd2aab (diff) | |
download | tqt3-feat/dedup-tqobject.tar.gz tqt3-feat/dedup-tqobject.zip |
Make TQConnectionList sharedfeat/dedup-tqobject
This commit fixes crashes caused by modifications of TQobject
connections from the slots invoked by its signals. Up to recent time
those were hidden by implementation specificities in
TQObject::activate_signal(), so they would appear only under quite
peculiar circumstances, but after attempts to de-duplicate the code they
surfaced up.
Besides that the patch de-duplicates some code in
TQObject::disconnectInternal().
Signed-off-by: Alexander Golubev <fatzer2@gmail.com>
-rw-r--r-- | src/kernel/ntqsignalslotimp.h | 19 | ||||
-rw-r--r-- | src/kernel/qobject.cpp | 113 |
2 files changed, 77 insertions, 55 deletions
diff --git a/src/kernel/ntqsignalslotimp.h b/src/kernel/ntqsignalslotimp.h index 375f8eaa8..7e6989197 100644 --- a/src/kernel/ntqsignalslotimp.h +++ b/src/kernel/ntqsignalslotimp.h @@ -47,7 +47,7 @@ #include "ntqptrvector.h" #endif // QT_H -class TQ_EXPORT TQConnectionList : public TQPtrList<TQConnection> +class TQ_EXPORT TQConnectionList : public TQPtrList<TQConnection>, public TQShared { public: TQConnectionList() : TQPtrList<TQConnection>() {} @@ -55,6 +55,23 @@ public: ~TQConnectionList() { clear(); } TQConnectionList &operator=(const TQConnectionList &list) { return (TQConnectionList&)TQPtrList<TQConnection>::operator=(list); } + + TQConnectionList *deepCopy() const { + TQConnectionList *rv = new TQConnectionList; + TQ_CHECK_PTR( rv ); + for( TQConnectionList::ConstIterator it = this->constBegin(), + end = this->constEnd(); + it!=end;++it + ) { + TQConnection *c = + new TQConnection((*it)->object(), (*it)->member(), + (*it)->memberName(), (*it)->memberType()); + + TQ_CHECK_PTR( c ); + rv->append(c); + } + return rv; + } }; class TQ_EXPORT TQConnectionListIt : public TQPtrListIterator<TQConnection> diff --git a/src/kernel/qobject.cpp b/src/kernel/qobject.cpp index c2907d553..9dc8f36b1 100644 --- a/src/kernel/qobject.cpp +++ b/src/kernel/qobject.cpp @@ -775,6 +775,9 @@ TQObject::~TQObject() removeObjFromList( obj->senderObjects, this ); } } + if( clist->deref() ) { + delete clist; + } } delete connections; connections = 0; @@ -1610,7 +1613,6 @@ TQConnectionList *TQObject::receivers( int signal ) const if ( !connections ) { TQObject* that = (TQObject*) this; that->connections = new TQSignalVec( signal+1 ); - that->connections->setAutoDelete( TRUE ); } if ( !connections->at( signal ) ) { TQConnectionList* clist = new TQConnectionList; @@ -2247,7 +2249,6 @@ void TQObject::connectInternal( const TQObject *sender, int signal_index, const if ( !s->connections ) { // create connections lookup table s->connections = new TQSignalVec( signal_index+1 ); TQ_CHECK_PTR( s->connections ); - s->connections->setAutoDelete( TRUE ); } TQConnectionList *clist = s->connections->at( signal_index ); @@ -2256,6 +2257,13 @@ void TQObject::connectInternal( const TQObject *sender, int signal_index, const TQ_CHECK_PTR( clist ); clist->setAutoDelete( TRUE ); s->connections->insert( signal_index, clist ); + } else if( clist->TQShared::count != 1 ) { // if we are not the sole owner, make a deep copy of the list + TQConnectionList *clistNew = clist->deepCopy(); + TQ_CHECK_PTR( clistNew ); + clistNew->setAutoDelete( TRUE ); + clist->deref(); + clist = clistNew; + s->connections->insert( signal_index , clist ); } TQMetaObject *rmeta = r->metaObject(); @@ -2273,6 +2281,7 @@ void TQObject::connectInternal( const TQObject *sender, int signal_index, const TQConnection *c = new TQConnection( r, member_index, rm ? rm->name : "qt_invoke", membcode ); TQ_CHECK_PTR( c ); clist->append( c ); + if ( !r->senderObjects ) { // create list of senders #ifdef TQT_THREAD_SUPPORT r->d->senderObjectListMutex->lock(); @@ -2487,69 +2496,48 @@ bool TQObject::disconnectInternal( const TQObject *sender, int signal_index, return FALSE; bool success = FALSE; - TQConnectionList *clist; - TQConnection *c; - if ( signal_index == -1 ) { - for ( int i = 0; i < (int) s->connections->size(); i++ ) { - clist = (*s->connections)[i]; // for all signals... - if ( !clist ) - continue; - c = clist->first(); - while ( c ) { // for all receivers... - if ( r == 0 ) { // remove all receivers - if (c->object()->senderObjects) { -#ifdef TQT_THREAD_SUPPORT - TQMutexLocker locker(c->object()->senderObjects->listMutex); -#endif // TQT_THREAD_SUPPORT - removeObjFromList( c->object()->senderObjects, s ); - } - success = TRUE; - c = clist->next(); - } else if ( r == c->object() && - ( (member_index == -1) || - ((member_index == c->member()) && (c->memberType() == membcode)) ) ) { - if (c->object()->senderObjects) { -#ifdef TQT_THREAD_SUPPORT - TQMutexLocker locker(c->object()->senderObjects->listMutex); -#endif // TQT_THREAD_SUPPORT - removeObjFromList( c->object()->senderObjects, s, TRUE ); - } - success = TRUE; - clist->remove(); - c = clist->current(); - } else { - c = clist->next(); - } - } - if ( r == 0 ) // disconnect all receivers - s->connections->insert( i, 0 ); - } - } else { - clist = s->connections->at( signal_index ); + + // A helper lambdata to disconnect the given signal + auto disconnecSignal = [s, r, membcode, member_index](int signal_index) -> bool { + bool rv = FALSE; + TQConnectionList *clist = s->connections->at( signal_index ); if ( !clist ) return FALSE; - c = clist->first(); + TQConnection *c = clist->first(); while ( c ) { // for all receivers... if ( r == 0 ) { // remove all receivers - if (c->object()->senderObjects) { + if (c->object()->senderObjects) { #ifdef TQT_THREAD_SUPPORT - TQMutexLocker locker(c->object()->senderObjects->listMutex); + TQMutexLocker locker(c->object()->senderObjects->listMutex); #endif // TQT_THREAD_SUPPORT - removeObjFromList( c->object()->senderObjects, s, TRUE ); - } - success = TRUE; + removeObjFromList( c->object()->senderObjects, s, TRUE ); + } + rv = TRUE; c = clist->next(); } else if ( r == c->object() && ( (member_index == -1) || - ((member_index == c->member()) && (c->memberType() == membcode)) ) ) { - if (c->object()->senderObjects) { + ((member_index == c->member()) && (c->memberType() == membcode)) ) ) + { + if (c->object()->senderObjects) { #ifdef TQT_THREAD_SUPPORT - TQMutexLocker locker(c->object()->senderObjects->listMutex); + TQMutexLocker locker(c->object()->senderObjects->listMutex); #endif // TQT_THREAD_SUPPORT - removeObjFromList( c->object()->senderObjects, s, TRUE ); - } - success = TRUE; + removeObjFromList( c->object()->senderObjects, s, TRUE ); + } + rv = TRUE; + + // if we are not the sole owner, deep-copy the list and use it instead of rhe + // current one. This needed in case we are already inside a slot which uses it. + if( clist->TQShared::count != 1 ) { + TQConnectionList *clistNew = clist->deepCopy(); + TQ_CHECK_PTR( clistNew ); + clistNew->setAutoDelete( TRUE ); + clistNew->at(clist->at()); // make current point to the same element + clist->deref(); + clist = clistNew; + s->connections->insert( signal_index , clist ); + } clist->remove(); c = clist->current(); } else { @@ -2557,8 +2545,22 @@ bool TQObject::disconnectInternal( const TQObject *sender, int signal_index, } } if ( r == 0 ) { // disconnect all receivers + if( clist->deref() ) { + delete clist; + } s->connections->insert( signal_index, 0 ); } + return rv; + }; + + if ( signal_index == -1 ) { + for ( int i = 0; i < (int) s->connections->size(); i++ ) { + if( disconnecSignal( i ) ) { + success = TRUE; + } + } + } else { + success = disconnecSignal( signal_index ); } return success; } @@ -2772,7 +2774,7 @@ void TQObject::activate_signal( TQConnectionList *clist, TQUObject *o ) if ( !clist ) { return; } - + clist->ref(); #ifndef TQT_NO_PRELIMINARY_SIGNAL_SPY if ( tqt_preliminary_signal_spy ) { qt_spy_signal( this, connections->findRef( clist), o ); @@ -2861,6 +2863,9 @@ void TQObject::activate_signal( TQConnectionList *clist, TQUObject *o ) if (sol) sol->listMutex->unlock(); #endif // TQT_THREAD_SUPPORT } + if( clist->deref() ) { + delete clist; + } } /*! |