summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichele Calgaro <michele.calgaro@yahoo.it>2024-08-23 23:40:14 +0900
committerMichele Calgaro <michele.calgaro@yahoo.it>2024-08-23 23:57:24 +0900
commitddce1c91f8582885497b463b24bac59f6fdfdf63 (patch)
tree52d4570fdcb8c1c2d21245fad88940b0020a2b88
parent82ecd83484c9fa1ede059986ab771e74e33e68ef (diff)
downloadtqt3-ddce1c91f8582885497b463b24bac59f6fdfdf63.tar.gz
tqt3-ddce1c91f8582885497b463b24bac59f6fdfdf63.zip
Improve handling of the global post event list in order to minimize possible crashes on exit.
Key points: 1. a TQPostEventList can now have an associated mutex, which is used in case of the global post event list (GPEL) 2. the lifetime of the GPEL is no longer associated to the lifetime of the TQApplication object, but rather extended to the lifetime of the main thread. The GPEL is a static local initialized on first access and destroyed when the global static object destructor is invoked 3. access to the GPEL after the TQApplication object has been destroyed has been minimized by protecting calls in ~TQObject() and ~TQWidget(). 4. special care was taken not to affect performances or unnecessarily create tons of unused TQMutexes This replaces PR #182. Technically it is still possibly unsafe due to the order of destruction of the globat static objects not being guaranteed across multiple compilation units, but the aforementioned changes should minimize (possible to zero) the chances of a SEGV happening. Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
-rw-r--r--src/kernel/qapplication.cpp159
-rw-r--r--src/kernel/tqobject.cpp5
-rw-r--r--src/kernel/tqwidget.cpp5
3 files changed, 92 insertions, 77 deletions
diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp
index a409fd45..d48805c3 100644
--- a/src/kernel/qapplication.cpp
+++ b/src/kernel/qapplication.cpp
@@ -377,10 +377,11 @@ int TQApplication::composedUnicode = 0;
TQMutex *TQApplication::tqt_mutex = 0;
TQMutex *tqt_sharedStringMutex = 0;
TQ_EXPORT TQMutex * tqt_sharedMetaObjectMutex = 0;
+
#ifdef QT_USE_GLIBMAINLOOP
TQMutex *tqt_timerListMutex = 0;
#endif // QT_USE_GLIBMAINLOOP
-static TQMutex *postevent_mutex = 0;
+
static TQt::HANDLE tqt_application_thread_id = 0;
TQ_EXPORT TQt::HANDLE tqt_get_application_thread_id()
{
@@ -595,7 +596,7 @@ static TQCoreApplicationThread tqt_main_thread;
// Definitions for posted events
struct TQPostEvent {
TQPostEvent( TQObject *r, TQEvent *e ): receiver( r ), event( e ) {}
- ~TQPostEvent() { delete event; }
+ ~TQPostEvent() { delete event; }
TQObject *receiver;
TQEvent *event;
};
@@ -603,36 +604,68 @@ struct TQPostEvent {
class TQ_EXPORT TQPostEventList : public TQPtrList<TQPostEvent>
{
public:
- TQPostEventList() : TQPtrList<TQPostEvent>() {}
- TQPostEventList( const TQPostEventList &list ) : TQPtrList<TQPostEvent>(list) {}
- ~TQPostEventList() { clear(); }
- TQPostEventList &operator=(const TQPostEventList &list)
- { return (TQPostEventList&)TQPtrList<TQPostEvent>::operator=(list); }
+ TQPostEventList(bool with_mutex = false) : TQPtrList<TQPostEvent>(), m_mutex(nullptr)
+ {
+#ifdef TQT_THREAD_SUPPORT
+ if (with_mutex)
+ {
+ m_mutex = new TQMutex(TRUE);
+ }
+#endif
+ }
+
+ ~TQPostEventList()
+ {
+ if (m_mutex)
+ {
+ delete m_mutex;
+ m_mutex = nullptr;
+ }
+ clear();
+ }
+
+ TQMutex* mutex() const { return m_mutex; }
+
+private:
+ TQMutex *m_mutex;
+
+ TQPostEventList(const TQPostEventList &) = delete;
+ TQPostEventList &operator=(const TQPostEventList &) = delete;
};
+
class TQ_EXPORT TQPostEventListIt : public TQPtrListIterator<TQPostEvent>
{
public:
TQPostEventListIt( const TQPostEventList &l ) : TQPtrListIterator<TQPostEvent>(l) {}
TQPostEventListIt &operator=(const TQPostEventListIt &i)
-{ return (TQPostEventListIt&)TQPtrListIterator<TQPostEvent>::operator=(i); }
+{
+ return (TQPostEventListIt&)TQPtrListIterator<TQPostEvent>::operator=(i); }
};
-static TQPostEventList *globalPostedEvents = 0; // list of posted events
+// The global list and its pointer are initialized in different functions
+// to optimize access to the list pointer in normal usage
+static TQPostEventList* InitGlobalPostedEventsList()
+{
+ static TQPostEventList _globalEventList(true);
+ _globalEventList.setAutoDelete(TRUE);
+ return &_globalEventList;
+}
+
+static TQPostEventList* GlobalPostedEvents()
+{
+ static TQPostEventList *_globalPostedEvents = InitGlobalPostedEventsList();
+ return _globalPostedEvents;
+}
uint qGlobalPostedEventsCount()
{
#ifdef TQT_THREAD_SUPPORT
- TQMutexLocker locker( postevent_mutex );
+ TQMutexLocker locker( GlobalPostedEvents()->mutex() );
#endif // TQT_THREAD_SUPPORT
- if (!globalPostedEvents) {
- return 0;
- }
- return globalPostedEvents->count();
+ return GlobalPostedEvents()->count();
}
-static TQSingleCleanupHandler<TQPostEventList> qapp_cleanup_events;
-
#ifndef TQT_NO_PALETTE
TQPalette *tqt_std_pal = 0;
@@ -1088,7 +1121,6 @@ void TQApplication::initialize( int argc, char **argv, bool enable_sm )
#ifdef QT_USE_GLIBMAINLOOP
tqt_timerListMutex = new TQMutex( TRUE );
#endif // QT_USE_GLIBMAINLOOP
- postevent_mutex = new TQMutex( TRUE );
tqt_application_thread_id = TQThread::currentThread();
#endif // TQT_THREAD_SUPPORT
@@ -1247,8 +1279,6 @@ TQApplication::~TQApplication()
#ifdef TQT_THREAD_SUPPORT
delete tqt_mutex;
tqt_mutex = 0;
- delete postevent_mutex;
- postevent_mutex = 0;
#endif // TQT_THREAD_SUPPORT
if( tqApp == this ) {
@@ -2538,33 +2568,31 @@ bool TQApplication::notify( TQObject *receiver, TQEvent *e )
if ( e->type() == TQEvent::ChildRemoved && receiver->postedEvents) {
#ifdef TQT_THREAD_SUPPORT
- TQMutexLocker locker( postevent_mutex );
+ TQMutexLocker locker( GlobalPostedEvents()->mutex() );
#endif // TQT_THREAD_SUPPORT
- if (globalPostedEvents) {
- // the TQObject destructor calls TQObject::removeChild, which calls
- // TQApplication::sendEvent() directly. this can happen while the event
- // loop is in the middle of posting events, and when we get here, we may
- // not have any more posted events for this object.
- if ( receiver->postedEvents ) {
- // if this is a child remove event and the child insert
- // hasn't been dispatched yet, kill that insert
- TQPostEventList * l = receiver->postedEvents;
- TQObject * c = ((TQChildEvent*)e)->child();
- TQPostEvent * pe;
- l->first();
- while( ( pe = l->current()) != 0 ) {
- if ( pe->event && pe->receiver == receiver &&
- pe->event->type() == TQEvent::ChildInserted &&
- ((TQChildEvent*)pe->event)->child() == c ) {
- pe->event->posted = FALSE;
- delete pe->event;
- pe->event = 0;
- l->remove();
- continue;
- }
- l->next();
+ // the TQObject destructor calls TQObject::removeChild, which calls
+ // TQApplication::sendEvent() directly. this can happen while the event
+ // loop is in the middle of posting events, and when we get here, we may
+ // not have any more posted events for this object.
+ if ( receiver->postedEvents ) {
+ // if this is a child remove event and the child insert
+ // hasn't been dispatched yet, kill that insert
+ TQPostEventList * l = receiver->postedEvents;
+ TQObject * c = ((TQChildEvent*)e)->child();
+ TQPostEvent * pe;
+ l->first();
+ while( ( pe = l->current()) != 0 ) {
+ if ( pe->event && pe->receiver == receiver &&
+ pe->event->type() == TQEvent::ChildInserted &&
+ ((TQChildEvent*)pe->event)->child() == c ) {
+ pe->event->posted = FALSE;
+ delete pe->event;
+ pe->event = 0;
+ l->remove();
+ continue;
}
+ l->next();
}
}
}
@@ -3386,16 +3414,9 @@ void TQApplication::postEvent( TQObject *receiver, TQEvent *event )
}
#ifdef TQT_THREAD_SUPPORT
- TQMutexLocker locker( postevent_mutex );
+ TQMutexLocker locker( GlobalPostedEvents()->mutex() );
#endif // TQT_THREAD_SUPPORT
- if ( !globalPostedEvents ) { // create list
- globalPostedEvents = new TQPostEventList;
- TQ_CHECK_PTR( globalPostedEvents );
- globalPostedEvents->setAutoDelete( TRUE );
- qapp_cleanup_events.set( &globalPostedEvents );
- }
-
if ( !receiver->postedEvents ) {
receiver->postedEvents = new TQPostEventList;
}
@@ -3479,7 +3500,7 @@ void TQApplication::postEvent( TQObject *receiver, TQEvent *event )
event->posted = TRUE;
TQPostEvent * pe = new TQPostEvent( receiver, event );
l->append( pe );
- globalPostedEvents->append( pe );
+ GlobalPostedEvents()->append( pe );
#ifdef TQT_THREAD_SUPPORT
// Wake up the receiver thread event loop
@@ -3535,24 +3556,20 @@ void TQApplication::sendPostedEvents( TQObject *receiver, int event_type )
}
#ifdef TQT_THREAD_SUPPORT
- TQMutexLocker locker( postevent_mutex );
+ TQMutexLocker locker( GlobalPostedEvents()->mutex() );
#endif
- if ( !globalPostedEvents || ( receiver && !receiver->postedEvents ) ) {
- return;
- }
-
bool sent = TRUE;
while ( sent ) {
sent = FALSE;
- if ( !globalPostedEvents || ( receiver && !receiver->postedEvents ) ) {
+ if (receiver && !receiver->postedEvents) {
return;
}
// if we have a receiver, use the local list. Otherwise, use the
// global list
- TQPostEventList * l = receiver ? receiver->postedEvents : globalPostedEvents;
+ TQPostEventList * l = receiver ? receiver->postedEvents : GlobalPostedEvents();
// okay. here is the tricky loop. be careful about optimizing
// this, it looks the way it does for good reasons.
@@ -3624,14 +3641,14 @@ void TQApplication::sendPostedEvents( TQObject *receiver, int event_type )
// clear the global list, i.e. remove everything that was
// delivered.
- if ( l == globalPostedEvents ) {
- globalPostedEvents->first();
- while( (pe=globalPostedEvents->current()) != 0 ) {
+ if ( l == GlobalPostedEvents() ) {
+ GlobalPostedEvents()->first();
+ while( (pe=GlobalPostedEvents()->current()) != 0 ) {
if ( pe->event ) {
- globalPostedEvents->next();
+ GlobalPostedEvents()->next();
}
else {
- globalPostedEvents->remove();
+ GlobalPostedEvents()->remove();
}
}
}
@@ -3673,7 +3690,7 @@ void TQApplication::removePostedEvents( TQObject *receiver, int event_type )
}
#ifdef TQT_THREAD_SUPPORT
- TQMutexLocker locker( postevent_mutex );
+ TQMutexLocker locker( GlobalPostedEvents()->mutex() );
#endif // TQT_THREAD_SUPPORT
// the TQObject destructor calls this function directly. this can
@@ -3726,18 +3743,10 @@ void TQApplication::removePostedEvent( TQEvent * event )
}
#ifdef TQT_THREAD_SUPPORT
- TQMutexLocker locker( postevent_mutex );
+ TQMutexLocker locker( GlobalPostedEvents()->mutex() );
#endif // TQT_THREAD_SUPPORT
- if ( !globalPostedEvents ) {
-#if defined(QT_DEBUG)
- tqDebug( "TQApplication::removePostedEvent: %p %d is posted: impossible",
- (void*)event, event->type() );
- return;
-#endif
- }
-
- TQPostEventListIt it( *globalPostedEvents );
+ TQPostEventListIt it( *GlobalPostedEvents() );
TQPostEvent * pe;
while( (pe = it.current()) != 0 ) {
++it;
diff --git a/src/kernel/tqobject.cpp b/src/kernel/tqobject.cpp
index ac7a405e..cfb026fb 100644
--- a/src/kernel/tqobject.cpp
+++ b/src/kernel/tqobject.cpp
@@ -747,7 +747,10 @@ TQObject::~TQObject()
if ( pendTimer ) { // might be pending timers
qKillTimer( this );
}
- TQApplication::removePostedEvents( this );
+ if ( tqApp )
+ {
+ TQApplication::removePostedEvents( this );
+ }
if ( isTree ) {
remove_tree( this ); // remove from global root list
isTree = FALSE;
diff --git a/src/kernel/tqwidget.cpp b/src/kernel/tqwidget.cpp
index ddc34c0e..0b27e256 100644
--- a/src/kernel/tqwidget.cpp
+++ b/src/kernel/tqwidget.cpp
@@ -1003,7 +1003,10 @@ TQWidget::~TQWidget()
childObjects = 0;
}
- TQApplication::removePostedEvents( this );
+ if ( tqApp )
+ {
+ TQApplication::removePostedEvents( this );
+ }
destroy(); // platform-dependent cleanup
if ( extra )