diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-05-14 19:34:10 -0500 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-05-14 19:34:10 -0500 |
commit | 4eba9b823832a5bab1acffeabc245b06fe113d75 (patch) | |
tree | 9ec81ead726a66066c6450c805beb8e233391a65 /src/kernel/qapplication.cpp | |
parent | be8413249bb8a6d8dc2cfc693d9c1037284fd251 (diff) | |
download | qt3-4eba9b823832a5bab1acffeabc245b06fe113d75.tar.gz qt3-4eba9b823832a5bab1acffeabc245b06fe113d75.zip |
Fix a number of threading data races
Add proper thread termination handler
This partially resolves Bug 1508
Diffstat (limited to 'src/kernel/qapplication.cpp')
-rw-r--r-- | src/kernel/qapplication.cpp | 142 |
1 files changed, 110 insertions, 32 deletions
diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp index fb531cb..63ddd1e 100644 --- a/src/kernel/qapplication.cpp +++ b/src/kernel/qapplication.cpp @@ -377,8 +377,13 @@ int QApplication::composedUnicode = 0; #ifdef QT_THREAD_SUPPORT QMutex *QApplication::qt_mutex = 0; -static QMutex *postevent_mutex = 0; -static Qt::HANDLE qt_application_thread_id = 0; +QMutex *qt_sharedStringMutex = 0; +Q_EXPORT QMutex * qt_sharedMetaObjectMutex = 0; +#ifdef QT_USE_GLIBMAINLOOP +QMutex *qt_timerListMutex = 0; +#endif // QT_USE_GLIBMAINLOOP +static QMutex *postevent_mutex = 0; +static Qt::HANDLE qt_application_thread_id = 0; Q_EXPORT Qt::HANDLE qt_get_application_thread_id() { return qt_application_thread_id; @@ -600,6 +605,10 @@ static QPostEventList *globalPostedEvents = 0; // list of posted events uint qGlobalPostedEventsCount() { +#ifdef QT_THREAD_SUPPORT + QMutexLocker locker( postevent_mutex ); +#endif // QT_THREAD_SUPPORT + if (!globalPostedEvents) { return 0; } @@ -1015,6 +1024,11 @@ void QApplication::initialize( int argc, char **argv ) { #ifdef QT_THREAD_SUPPORT qt_mutex = new QMutex( TRUE ); + qt_sharedStringMutex = new QMutex( TRUE ); + qt_sharedMetaObjectMutex = new QMutex( TRUE ); +#ifdef QT_USE_GLIBMAINLOOP + qt_timerListMutex = new QMutex( TRUE ); +#endif // QT_USE_GLIBMAINLOOP postevent_mutex = new QMutex( TRUE ); qt_application_thread_id = QThread::currentThread(); #endif // QT_THREAD_SUPPORT @@ -1184,6 +1198,17 @@ QApplication::~QApplication() session_key = 0; #endif //QT_NO_SESSIONMANAGER +#ifdef QT_THREAD_SUPPORT + delete qt_sharedMetaObjectMutex; + qt_sharedMetaObjectMutex = 0; + delete qt_sharedStringMutex; + qt_sharedStringMutex = 0; +#ifdef QT_USE_GLIBMAINLOOP + delete qt_timerListMutex; + qt_timerListMutex = 0; +#endif // QT_USE_GLIBMAINLOOP +#endif // QT_THREAD_SUPPORT + qt_explicit_app_style = FALSE; qt_app_has_font = FALSE; app_tracking = 0; @@ -2425,35 +2450,40 @@ bool QApplication::notify( QObject *receiver, QEvent *e ) return FALSE; } - if ( e->type() == QEvent::ChildRemoved && receiver->postedEvents && globalPostedEvents) { + if ( receiver && (e->type() == QEvent::Destroy) ) { + return TRUE; + } + if ( e->type() == QEvent::ChildRemoved && receiver->postedEvents) { #ifdef QT_THREAD_SUPPORT QMutexLocker locker( postevent_mutex ); #endif // QT_THREAD_SUPPORT - // the QObject destructor calls QObject::removeChild, which calls - // QApplication::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 - QPostEventList * l = receiver->postedEvents; - QObject * c = ((QChildEvent*)e)->child(); - QPostEvent * pe; - l->first(); - while( ( pe = l->current()) != 0 ) { - if ( pe->event && pe->receiver == receiver && - pe->event->type() == QEvent::ChildInserted && - ((QChildEvent*)pe->event)->child() == c ) { - pe->event->posted = FALSE; - delete pe->event; - pe->event = 0; - l->remove(); - continue; + if (globalPostedEvents) { + // the QObject destructor calls QObject::removeChild, which calls + // QApplication::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 + QPostEventList * l = receiver->postedEvents; + QObject * c = ((QChildEvent*)e)->child(); + QPostEvent * pe; + l->first(); + while( ( pe = l->current()) != 0 ) { + if ( pe->event && pe->receiver == receiver && + pe->event->type() == QEvent::ChildInserted && + ((QChildEvent*)pe->event)->child() == c ) { + pe->event->posted = FALSE; + delete pe->event; + pe->event = 0; + l->remove(); + continue; + } + l->next(); + } } - l->next(); - } } } @@ -3545,8 +3575,9 @@ void QApplication::removePostedEvents( QObject *receiver ) void QApplication::removePostedEvents( QObject *receiver, int event_type ) { - if ( !receiver ) + if ( !receiver ) { return; + } #ifdef QT_THREAD_SUPPORT QMutexLocker locker( postevent_mutex ); @@ -3556,8 +3587,9 @@ void QApplication::removePostedEvents( QObject *receiver, int event_type ) // 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 ( !receiver->postedEvents ) { return; + } // iterate over the object-specifc list and delete the events. // leave the QPostEvent objects; they'll be deleted by @@ -3596,8 +3628,13 @@ void QApplication::removePostedEvents( QObject *receiver, int event_type ) void QApplication::removePostedEvent( QEvent * event ) { - if ( !event || !event->posted ) + if ( !event || !event->posted ) { return; + } + +#ifdef QT_THREAD_SUPPORT + QMutexLocker locker( postevent_mutex ); +#endif // QT_THREAD_SUPPORT if ( !globalPostedEvents ) { #if defined(QT_DEBUG) @@ -3607,10 +3644,6 @@ void QApplication::removePostedEvent( QEvent * event ) #endif } -#ifdef QT_THREAD_SUPPORT - QMutexLocker locker( postevent_mutex ); -#endif // QT_THREAD_SUPPORT - QPostEventListIt it( *globalPostedEvents ); QPostEvent * pe; while( (pe = it.current()) != 0 ) { @@ -3696,6 +3729,51 @@ void QApplication::removePostedEvent( QEvent * event ) } } +void qThreadTerminationHandlerRecursive( QObject* object, QThread* originThread, QThread* destinationThread ) { +#ifdef QT_THREAD_SUPPORT + QThread* objectThread = object->contextThreadObject(); + if (objectThread != destinationThread) { + QThread::CleanupType cleanupType = objectThread->cleanupType(); + if (cleanupType == QThread::CleanupMergeObjects) { + object->moveToThread(destinationThread); + } + else if (cleanupType == QThread::CleanupNone) { + // Do nothing +#if defined(QT_DEBUG) + qDebug( "QApplication::threadTerminationHandler: object %p still owned by thread %p at thread termination!", object, objectThread); +#endif // QT_DEBUG + } + else { + // Do nothing +#if defined(QT_DEBUG) + qDebug( "QApplication::threadTerminationHandler: invalid thread termination cleanup type %d specified", cleanupType); +#endif // QT_DEBUG + } + } + QObjectList children = object->childrenListObject(); + QObject *childObject; + for ( childObject = children.first(); childObject; childObject = children.next() ) { + qThreadTerminationHandlerRecursive(childObject, originThread, destinationThread); + } +#endif // QT_THREAD_SUPPORT +} + +/*!\internal + + Migrates all objects from the specified thread in preparation + for thread destruction. + */ +void QApplication::threadTerminationHandler( QThread *originThread ) { +#ifdef QT_THREAD_SUPPORT + QMutexLocker locker( qt_mutex ); + QThread* destinationThread = guiThread(); + const QObjectList* objects = QObject::objectTrees(); + for ( QObjectListIt objectit( *objects ) ; *objectit; ++objectit ) { + qThreadTerminationHandlerRecursive((*objectit), originThread, destinationThread); + } +#endif // QT_THREAD_SUPPORT +} + /*!\internal Sets the active window in reaction to a system event. Call this |