summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Golubev <fatzer2@gmail.com>2024-03-16 08:14:54 +0300
committerAlexander Golubev <fatzer2@gmail.com>2024-03-16 08:14:54 +0300
commit6250349b0b0a48a23b6cd847e70330e90c812bcc (patch)
treee376dcf0d886faafcf95eb5454c3ecd7ca2943b1
parent24eb408f6a99f2b43ec6980e903a5d3525cd2aab (diff)
downloadtqt3-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.h19
-rw-r--r--src/kernel/qobject.cpp113
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;
+ }
}
/*!