diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 148b60d4abc..d5c5e33cc97 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -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 diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 14c6490c1e7..36112afd4df 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -140,12 +140,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 { @@ -418,7 +426,6 @@ void QThreadPrivate::cleanup() d->interruptionRequested.store(false, std::memory_order_relaxed); d->isInFinish = false; - d->data->threadId.storeRelaxed(nullptr); d->thread_done.wakeAll(); }); @@ -828,14 +835,14 @@ bool QThread::wait(QDeadlineTimer deadline) Q_D(QThread); QMutexLocker locker(&d->mutex); + if (d->finished || !d->running) + return true; + if (isCurrentThread()) { qWarning("QThread::wait: Thread tried to wait on itself"); return false; } - if (d->finished || !d->running) - return true; - return d->wait(locker, deadline); } @@ -848,7 +855,6 @@ bool QThreadPrivate::wait(QMutexLocker &locker, QDeadlineTimer deadline) if (!d->thread_done.wait(locker.mutex(), deadline)) return false; } - Q_ASSERT(d->data->threadId.loadRelaxed() == nullptr); return true; } diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp index 5dc445d44f2..a031e6a54d0 100644 --- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp +++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp @@ -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