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>
pull/183/head
Michele Calgaro 3 months ago
parent 82ecd83484
commit ddce1c91f8
Signed by: MicheleC
GPG Key ID: 2A75B7CA8ADED5CF

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

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

@ -1003,7 +1003,10 @@ TQWidget::~TQWidget()
childObjects = 0;
}
TQApplication::removePostedEvents( this );
if ( tqApp )
{
TQApplication::removePostedEvents( this );
}
destroy(); // platform-dependent cleanup
if ( extra )

Loading…
Cancel
Save