mirror of https://github.com/qt/qtbase.git
QThread/Unix: do clean up the QAdoptedThread for the main thread
Commit1ed0dd88a3
("QThread/Unix: make QThreadPrivate::finish() be called much later") introduced this problem. Commit4fabde349f
split the thread termination in two phases, but did not fix this. This re-applies commit950b35cf97
("Clear the current thread data for the main thread"), which was reverted in commit7dc622290b
("Make sure QThreadData and QAdoptedThread object is destroyed at app exit"), both from Qt 5.1. Between Qt 5.1 and 6.7, the responsibility of clearing the QAdoptedThread for the main thread was split: it could occur either in ~QCoreApplicationData if exit() was called in that thread or in ~QThreadData() if it wasn't (e.g., when the Qt "main thread" is not main()'s thread): * frame #0: 0x0000000101db8a28 QtCore`QAdoptedThread::~QAdoptedThread(this=0x000060000176c070) at qthread.cpp:139:1 frame #1: 0x0000000101db81eb QtCore`QThreadData::~QThreadData(this=0x0000600002468000) at qthread.cpp:82:5 frame #2: 0x0000000101db8379 QtCore`QThreadData::~QThreadData(this=0x0000600002468000) at qthread.cpp:57:1 frame #3: 0x0000000101db841c QtCore`QThreadData::deref(this=0x0000600002468000) at qthread.cpp:108:9 frame #4: 0x0000000101f4ec79 QtCore`destroy_current_thread_data(p=0x0000600002468000) at qthread_unix.cpp:104:11 This commit centralizes and gives ~QThreadData() the exclusive responsibility. That requires not resetting QThreadData::threadId so ~QThreadData can know it is theMainThread. Fixes: QTBUG-130895 Task-number: QTBUG-129927 Task-number: QTBUG-129846 Task-number: QTBUG-130341 Task-number: QTBUG-117996 Pick-to: 6.8 Change-Id: Ie3f3cbdc5523837b505cfffd95fba5e6498b5069 Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
This commit is contained in:
parent
9bac90db46
commit
65093a84c2
|
@ -368,14 +368,16 @@ Q_CONSTINIT uint QCoreApplicationPrivate::attribs =
|
|||
(1 << Qt::AA_SynthesizeMouseForUnhandledTouchEvents) |
|
||||
(1 << Qt::AA_SynthesizeMouseForUnhandledTabletEvents);
|
||||
|
||||
struct QCoreApplicationData {
|
||||
struct QCoreApplicationData
|
||||
{
|
||||
QCoreApplicationData() noexcept {
|
||||
applicationNameSet = false;
|
||||
applicationVersionSet = false;
|
||||
}
|
||||
~QCoreApplicationData() {
|
||||
#ifndef QT_NO_QOBJECT
|
||||
#if !defined(QT_NO_QOBJECT) && defined(Q_OS_WIN)
|
||||
// cleanup the QAdoptedThread created for the main() thread
|
||||
// (for Unix systems, see qthread_unix.cpp:set_thread_data())
|
||||
if (auto *t = QCoreApplicationPrivate::theMainThread.loadAcquire()) {
|
||||
QThreadData *data = QThreadData::get2(t);
|
||||
data->deref(); // deletes the data and the adopted thread
|
||||
|
|
|
@ -165,12 +165,20 @@ static QThreadData *get_thread_data()
|
|||
return currentThreadData;
|
||||
}
|
||||
|
||||
#if QT_CONFIG(broken_threadlocal_dtors)
|
||||
// The destructors registered with pthread_key_create() below are NOT run from
|
||||
// exit(), so we must also use atexit().
|
||||
static void destroy_main_thread_data()
|
||||
{
|
||||
if (QThreadData *d = get_thread_data())
|
||||
destroy_current_thread_data(d);
|
||||
}
|
||||
Q_DESTRUCTOR_FUNCTION(destroy_main_thread_data)
|
||||
#endif
|
||||
|
||||
static void set_thread_data(QThreadData *data)
|
||||
{
|
||||
// Only activate the late cleanup for auxiliary threads. We can't use
|
||||
// QThread::isMainThread() here because theMainThreadId will not have been
|
||||
// set yet.
|
||||
if (data && QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
|
||||
if (data) {
|
||||
if constexpr (QT_CONFIG(broken_threadlocal_dtors)) {
|
||||
static pthread_key_t tls_key;
|
||||
struct TlsKey {
|
||||
|
@ -851,7 +859,6 @@ void QThread::terminate()
|
|||
static void wakeAllInternal(QThreadPrivate *d)
|
||||
{
|
||||
d->threadState = QThreadPrivate::Finished;
|
||||
d->data->threadId.storeRelaxed(nullptr);
|
||||
if (d->waiters)
|
||||
d->thread_done.wakeAll();
|
||||
}
|
||||
|
@ -867,16 +874,16 @@ bool QThread::wait(QDeadlineTimer deadline)
|
|||
Q_D(QThread);
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
if (isCurrentThread()) {
|
||||
qWarning("QThread::wait: Thread tried to wait on itself");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (d->threadState == QThreadPrivate::NotStarted)
|
||||
return true;
|
||||
if (d->threadState == QThreadPrivate::Finished)
|
||||
return true;
|
||||
|
||||
if (isCurrentThread()) {
|
||||
qWarning("QThread::wait: Thread tried to wait on itself");
|
||||
return false;
|
||||
}
|
||||
|
||||
return d->wait(locker, deadline);
|
||||
}
|
||||
|
||||
|
@ -949,7 +956,6 @@ bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
|
|||
}
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
Q_ASSERT(!result || data->threadId.loadRelaxed() == nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1065,9 +1065,22 @@ static void createQObjectOnDestruction()
|
|||
// QThread) after the last QObject has been destroyed (especially after
|
||||
// QCoreApplication has).
|
||||
|
||||
#if !defined(QT_QGUIAPPLICATIONTEST) && !defined(Q_OS_WIN) && !defined(Q_OS_VXWORKS)
|
||||
// QCoreApplicationData's global static destructor has run and cleaned up
|
||||
// the QAdoptedThread.
|
||||
#if defined(QT_QGUIAPPLICATIONTEST)
|
||||
// If we've linked to QtGui, we make no representations about there being
|
||||
// global static (not Q_GLOBAL_STATIC) variables that are QObject.
|
||||
#elif QT_CONFIG(broken_threadlocal_dtors)
|
||||
// With broken thread-local destructors, we cannot guarantee the ordering
|
||||
// between thread_local destructors and static-lifetime destructors (hence
|
||||
// why they're broken).
|
||||
//
|
||||
// On Unix systems, we use a Q_DESTRUCTOR_FUNCTION in qthread_unix.cpp to
|
||||
// work around the issue, but that means it cannot have run yet.
|
||||
//
|
||||
// This variable is set on Windows too, even though the nature of the
|
||||
// problem is different.
|
||||
#else
|
||||
// The thread_local destructor in qthread_unix.cpp has run so the
|
||||
// QAdoptedThread must have been cleaned up.
|
||||
if (theMainThreadIsSet())
|
||||
qFatal("theMainThreadIsSet() returned true; some QObject must have leaked");
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue