QThread/Unix: move the pthread_key to a file-scope static

So that the pthread_key is destroyed much later than now, at QtCore
unload time instead of a bit earlier in exit(). That's important so it
runs later than the Q_DESTRUCTOR_FUNCTION for QLibraryStore
(qlibrary.cpp), which is what unloads plugins, whose unload-time
destructors may be attempting to quit() & wait() for their worker
threads.

I had to keep the destruction of the exiting thread's adopted thread
where it was: a function-local static's destructor. As noted in the
comment added by 1da7558bfd7626bcc40a214a90ae5027f32f6c7f, we need
QThreadData::cleanup() to run before the libraries start to unload
because we need to delete the event dispatcher.

Init priority 10 will place it after the QHash random seed and qsimd
initialization, on ELF systems and on Windows. On other systems (incl.
Apple ones), the order probably depends on the order of the files in the
CMakeLists.txt. I thought that would mean the destructor for thread/
would run before plugin/ but that apparently is not the case. But that's
fragile.

Amends 1da7558bfd7626bcc40a214a90ae5027f32f6c7f, which amended other
things...

Fixes: QTBUG-132697
Task-number: QTBUG-102984
Task-number: QTBUG-132381
Pick-to: 6.8
Change-Id: Id7263d6ffe7a5949cd84e35d942ad0e02df1b455
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit 2f69a05bd0cd7ce63890f709ff3ed7a4f78acd70)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Thiago Macieira 2025-01-09 18:10:12 -03:00 committed by Qt Cherry-pick Bot
parent ea6d467c05
commit 4f6c2fd9d7

View File

@ -140,6 +140,12 @@ static void destroy_current_thread_data(void *p)
QThreadData *data = static_cast<QThreadData *>(p);
QThread *thread = data->thread.loadAcquire();
#ifdef Q_OS_APPLE
// apparent runtime bug: the trivial has been cleared and we end up
// recreating the QThreadData
currentThreadData = data;
#endif
if (data->isAdopted) {
// If this is an adopted thread, then QThreadData owns the QThread and
// this is very likely the last reference. These pointers cannot be
@ -173,21 +179,32 @@ static QThreadData *get_thread_data()
return currentThreadData;
}
namespace {
struct PThreadTlsKey
{
pthread_key_t key;
PThreadTlsKey() noexcept { pthread_key_create(&key, destroy_current_thread_data); }
~PThreadTlsKey() { pthread_key_delete(key); }
};
}
#if QT_SUPPORTS_INIT_PRIORITY
Q_DECL_INIT_PRIORITY(10)
#endif
static PThreadTlsKey pthreadTlsKey; // intentional non-trivial init & destruction
static void set_thread_data(QThreadData *data) noexcept
{
if (data) {
static pthread_key_t tls_key;
struct TlsKey {
TlsKey() noexcept { pthread_key_create(&tls_key, destroy_current_thread_data); }
~TlsKey()
{
if (QThreadData *data = currentThreadData)
// As noted above: one global static for the thread that called
// ::exit() (which may not be a Qt thread) and the pthread_key_t for
// all others.
static struct Cleanup {
~Cleanup() {
if (QThreadData *data = get_thread_data())
destroy_current_thread_data(data);
pthread_key_delete(tls_key);
}
};
static TlsKey currentThreadCleanup;
pthread_setspecific(tls_key, data);
} currentThreadCleanup;
pthread_setspecific(pthreadTlsKey.key, data);
}
currentThreadData = data;
}