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 9 months ago
parent 24eb408f6a
commit 6250349b0b

@ -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>

@ -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;
}
}
/*!

Loading…
Cancel
Save