Make TQConnectionList shared

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>
feat/dedup-tqobject
Alexander Golubev 8 months ago
parent 24eb408f6a
commit 6250349b0b

@ -47,7 +47,7 @@
#include "ntqptrvector.h" #include "ntqptrvector.h"
#endif // QT_H #endif // QT_H
class TQ_EXPORT TQConnectionList : public TQPtrList<TQConnection> class TQ_EXPORT TQConnectionList : public TQPtrList<TQConnection>, public TQShared
{ {
public: public:
TQConnectionList() : TQPtrList<TQConnection>() {} TQConnectionList() : TQPtrList<TQConnection>() {}
@ -55,6 +55,23 @@ public:
~TQConnectionList() { clear(); } ~TQConnectionList() { clear(); }
TQConnectionList &operator=(const TQConnectionList &list) TQConnectionList &operator=(const TQConnectionList &list)
{ return (TQConnectionList&)TQPtrList<TQConnection>::operator=(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> class TQ_EXPORT TQConnectionListIt : public TQPtrListIterator<TQConnection>

@ -775,6 +775,9 @@ TQObject::~TQObject()
removeObjFromList( obj->senderObjects, this ); removeObjFromList( obj->senderObjects, this );
} }
} }
if( clist->deref() ) {
delete clist;
}
} }
delete connections; delete connections;
connections = 0; connections = 0;
@ -1610,7 +1613,6 @@ TQConnectionList *TQObject::receivers( int signal ) const
if ( !connections ) { if ( !connections ) {
TQObject* that = (TQObject*) this; TQObject* that = (TQObject*) this;
that->connections = new TQSignalVec( signal+1 ); that->connections = new TQSignalVec( signal+1 );
that->connections->setAutoDelete( TRUE );
} }
if ( !connections->at( signal ) ) { if ( !connections->at( signal ) ) {
TQConnectionList* clist = new TQConnectionList; 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 if ( !s->connections ) { // create connections lookup table
s->connections = new TQSignalVec( signal_index+1 ); s->connections = new TQSignalVec( signal_index+1 );
TQ_CHECK_PTR( s->connections ); TQ_CHECK_PTR( s->connections );
s->connections->setAutoDelete( TRUE );
} }
TQConnectionList *clist = s->connections->at( signal_index ); 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 ); TQ_CHECK_PTR( clist );
clist->setAutoDelete( TRUE ); clist->setAutoDelete( TRUE );
s->connections->insert( signal_index, clist ); 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(); 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 ); TQConnection *c = new TQConnection( r, member_index, rm ? rm->name : "qt_invoke", membcode );
TQ_CHECK_PTR( c ); TQ_CHECK_PTR( c );
clist->append( c ); clist->append( c );
if ( !r->senderObjects ) { // create list of senders if ( !r->senderObjects ) { // create list of senders
#ifdef TQT_THREAD_SUPPORT #ifdef TQT_THREAD_SUPPORT
r->d->senderObjectListMutex->lock(); r->d->senderObjectListMutex->lock();
@ -2487,49 +2496,15 @@ bool TQObject::disconnectInternal( const TQObject *sender, int signal_index,
return FALSE; return FALSE;
bool success = FALSE; bool success = FALSE;
TQConnectionList *clist;
TQConnection *c; // A helper lambdata to disconnect the given signal
if ( signal_index == -1 ) { auto disconnecSignal = [s, r, membcode, member_index](int signal_index) -> bool {
for ( int i = 0; i < (int) s->connections->size(); i++ ) { bool rv = FALSE;
clist = (*s->connections)[i]; // for all signals... TQConnectionList *clist = s->connections->at( signal_index );
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 );
if ( !clist ) if ( !clist )
return FALSE; return FALSE;
c = clist->first(); TQConnection *c = clist->first();
while ( c ) { // for all receivers... while ( c ) { // for all receivers...
if ( r == 0 ) { // remove all receivers if ( r == 0 ) { // remove all receivers
if (c->object()->senderObjects) { if (c->object()->senderObjects) {
@ -2538,18 +2513,31 @@ bool TQObject::disconnectInternal( const TQObject *sender, int signal_index,
#endif // TQT_THREAD_SUPPORT #endif // TQT_THREAD_SUPPORT
removeObjFromList( c->object()->senderObjects, s, TRUE ); removeObjFromList( c->object()->senderObjects, s, TRUE );
} }
success = TRUE; rv = TRUE;
c = clist->next(); c = clist->next();
} else if ( r == c->object() && } else if ( r == c->object() &&
( (member_index == -1) || ( (member_index == -1) ||
((member_index == c->member()) && (c->memberType() == membcode)) ) ) { ((member_index == c->member()) && (c->memberType() == membcode)) ) )
{
if (c->object()->senderObjects) { if (c->object()->senderObjects) {
#ifdef TQT_THREAD_SUPPORT #ifdef TQT_THREAD_SUPPORT
TQMutexLocker locker(c->object()->senderObjects->listMutex); TQMutexLocker locker(c->object()->senderObjects->listMutex);
#endif // TQT_THREAD_SUPPORT #endif // TQT_THREAD_SUPPORT
removeObjFromList( c->object()->senderObjects, s, TRUE ); removeObjFromList( c->object()->senderObjects, s, TRUE );
} }
success = 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(); clist->remove();
c = clist->current(); c = clist->current();
} else { } else {
@ -2557,8 +2545,22 @@ bool TQObject::disconnectInternal( const TQObject *sender, int signal_index,
} }
} }
if ( r == 0 ) { // disconnect all receivers if ( r == 0 ) { // disconnect all receivers
if( clist->deref() ) {
delete clist;
}
s->connections->insert( signal_index, 0 ); 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; return success;
} }
@ -2772,7 +2774,7 @@ void TQObject::activate_signal( TQConnectionList *clist, TQUObject *o )
if ( !clist ) { if ( !clist ) {
return; return;
} }
clist->ref();
#ifndef TQT_NO_PRELIMINARY_SIGNAL_SPY #ifndef TQT_NO_PRELIMINARY_SIGNAL_SPY
if ( tqt_preliminary_signal_spy ) { if ( tqt_preliminary_signal_spy ) {
qt_spy_signal( this, connections->findRef( clist), o ); 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(); if (sol) sol->listMutex->unlock();
#endif // TQT_THREAD_SUPPORT #endif // TQT_THREAD_SUPPORT
} }
if( clist->deref() ) {
delete clist;
}
} }
/*! /*!

Loading…
Cancel
Save