summaryrefslogtreecommitdiffstats
path: root/src/kernel/qapplication.cpp
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2013-05-14 19:34:10 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2013-05-14 19:34:10 -0500
commit4eba9b823832a5bab1acffeabc245b06fe113d75 (patch)
tree9ec81ead726a66066c6450c805beb8e233391a65 /src/kernel/qapplication.cpp
parentbe8413249bb8a6d8dc2cfc693d9c1037284fd251 (diff)
downloadqt3-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.cpp142
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