Make qAddPostRoutine & family thread-safe

If one wants to add them on demand, threads may have started, so these
functions should be thread-safe. That includes the calling of the
registered functions: some other thread could be adding post routines
too. Of course, if you're racing, it's your own fault, but we need to
support the routines registered with qAddPostRoutine adding more post
routines.

[ChangeLog][QtCore] qAddPostRoutine() and qRemovePostRoutine() are now
thread-safe.

Task-number: QTBUG-62915
Change-Id: I38341f8155354cc4a776fffd14dffa68bde8345d
Reviewed-by: David Faure <david.faure@kdab.com>
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
bb10
Thiago Macieira 2017-08-31 09:15:28 -07:00
parent 362dcb4759
commit ca92ee2518
1 changed files with 32 additions and 8 deletions

View File

@ -263,7 +263,7 @@ Q_GLOBAL_STATIC(QStartUpFuncList, preRList)
typedef QList<QtCleanUpFunction> QVFuncList;
Q_GLOBAL_STATIC(QVFuncList, postRList)
#ifndef QT_NO_QOBJECT
static QBasicMutex globalPreRoutinesMutex;
static QBasicMutex globalRoutinesMutex;
#endif
/*!
@ -280,7 +280,7 @@ void qAddPreRoutine(QtStartUpFunction p)
// Due to C++11 parallel dynamic initialization, this can be called
// from multiple threads.
#ifndef QT_NO_THREAD
QMutexLocker locker(&globalPreRoutinesMutex);
QMutexLocker locker(&globalRoutinesMutex);
#endif
if (QCoreApplication::instance())
p();
@ -292,6 +292,9 @@ void qAddPostRoutine(QtCleanUpFunction p)
QVFuncList *list = postRList();
if (!list)
return;
#ifndef QT_NO_THREAD
QMutexLocker locker(&globalRoutinesMutex);
#endif
list->prepend(p);
}
@ -300,6 +303,9 @@ void qRemovePostRoutine(QtCleanUpFunction p)
QVFuncList *list = postRList();
if (!list)
return;
#ifndef QT_NO_THREAD
QMutexLocker locker(&globalRoutinesMutex);
#endif
list->removeAll(p);
}
@ -309,7 +315,7 @@ static void qt_call_pre_routines()
return;
#ifndef QT_NO_THREAD
QMutexLocker locker(&globalPreRoutinesMutex);
QMutexLocker locker(&globalRoutinesMutex);
#endif
QVFuncList *list = &(*preRList);
// Unlike qt_call_post_routines, we don't empty the list, because
@ -324,9 +330,21 @@ void Q_CORE_EXPORT qt_call_post_routines()
if (!postRList.exists())
return;
QVFuncList *list = &(*postRList);
while (!list->isEmpty())
(list->takeFirst())();
forever {
QVFuncList list;
{
// extract the current list and make the stored list empty
#ifndef QT_NO_THREAD
QMutexLocker locker(&globalRoutinesMutex);
#endif
qSwap(*postRList, list);
}
if (list.isEmpty())
break;
for (QtCleanUpFunction f : qAsConst(list))
f();
}
}
@ -2864,6 +2882,7 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc
/*!
\fn void qAddPostRoutine(QtCleanUpFunction ptr)
\threadsafe
\relates QCoreApplication
Adds a global routine that will be called from the QCoreApplication
@ -2877,10 +2896,10 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc
\snippet code/src_corelib_kernel_qcoreapplication.cpp 4
Note that for an application- or module-wide cleanup, qaddPostRoutine()
Note that for an application- or module-wide cleanup, qAddPostRoutine()
is often not suitable. For example, if the program is split into dynamically
loaded modules, the relevant module may be unloaded long before the
QCoreApplication destructor is called. In such cases, if using qaddPostRoutine()
QCoreApplication destructor is called. In such cases, if using qAddPostRoutine()
is still desirable, qRemovePostRoutine() can be used to prevent a routine
from being called by the QCoreApplication destructor. For example, if that
routine was called before the module was unloaded.
@ -2896,11 +2915,14 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc
By selecting the right parent object, this can often be made to
clean up the module's data at the right moment.
\note This function has been thread-safe since Qt 5.10.
\sa qRemovePostRoutine()
*/
/*!
\fn void qRemovePostRoutine(QtCleanUpFunction ptr)
\threadsafe
\relates QCoreApplication
\since 5.3
@ -2909,6 +2931,8 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc
must have been previously added to the list by a call to
qAddPostRoutine(), otherwise this function has no effect.
\note This function has been thread-safe since Qt 5.10.
\sa qAddPostRoutine()
*/