QThread/Unix: refactor to split QThreadPrivate::finish() in two phases
Commit 1ed0dd88a32cd2c5ae100b48e14ff55bcbb652e6 moved the finish()
functionality from immediately after run() returns to the time of
thread-local destruction, to make sure that user destructors didn't run
after our cleaning up. But as a side effect, it made other user code run
too late, after some thread-local statics had been destroyed.
This is a common practice, which causes the destructor for worker to run
too late:
worker->moveToThread(thread);
...
QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
QObject::connect(thread, &QThread::finished, worker, &QObject::deleteLater);
This commit splits the cleanup in two phases: QThreadPrivate::finish(),
which runs immediately after run() and will call back out to user code
(finished() signal and delivery of deleteLater()), and cleanup() that
cleans up the QThread{Private,Data} state and destroys the event
dispatcher. That destruction is the only call out to user code.
I've removed the complex mix of pre-C++11 pthread_setspecific() content
and C++11 thread_local variables in favor of using one or the other, not
both. We prefer the thread-local for future-proofing and simplicity, on
platforms where we can verify this C++11 feature works, and because it
allows us to clean up QThreadData and the event dispatcher as late as
possible. (There's some code that runs even later, such as pthread TLS
destructors, used by Glib's GMainLoop)
Unfortunately, we can't use it everywhere. The commit above had already
noticed QNX has a problem and recent bug reports have shown other
platforms (Solaris, MUSL libc) that, 13 years after the ratification of
the standard, still have broken support, so we use pthread for them and
we call cleanup() from within finish() (that is, no late cleaning-up,
retaining the status quo from Qt 4 and 5). See QTBUG-129846 for an
analysis.
Drive-by moving the resetting of thread priority to after finished() is
emitted.
[ChangeLog][QtCore][QThread] Restored the Qt 6.7 timing of when the
finished() signal is emitted relative to the destruction of thread_local
variables. Qt 6.8.0 contained a change that moved this signal to a later
time on most Unix systems, which has caused problems with the order in
which those variables were accessed. The destruction of the event
dispatcher is kept at this late stage, wherever possible.
Fixes: QTBUG-129927
Fixes: QTBUG-129846
Fixes: QTBUG-130341
Task-number: QTBUG-117996
Pick-to: 6.8
Change-Id: Ie5e40dd18faa05d8f777fffdf7dc30fc4fe0c7e9
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2024-10-15 16:17:39 +00:00
|
|
|
// Copyright (C) 2024 Intel Corporation
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
#include <stddef.h>
|
|
|
|
|
Enable broken_threadlocal_dtors for VxWorks
Changes applied in commit 4fabde349f16b59f37568da2a4c050c6dd53a34e broke
VxWorks tests and examples, many of which crash with error:
```
pthreadLib: unable to create POSIX thread internal attributes.
```
This error appeared in multiple tests, but was tested on tst_QSignalSpy,
where it was 100% reproducible (I haven't check other tests for
reproducibility).
This above error is printed when VxWorks task starts and initializes its
pthread containers. Pthread starting procedure results in error
`S_objLib_OBJ_ID_ERROR`, on which documentation states that it means
"The <tid> parameter is an invalid task ID". This happens because
VxWorks pthread implementation clears its internal data, and only then
passes control to `taskExit` system procedure, which calls thread_local
destructors. Any calls to `pthread` routines which require current
thread internal data ends with error and termination.
While VxWorks uses clang internally, it implements `__cxa_thread_atexit`
and `__cxa_thread_atexit_impl`, which makes it pass `TEST_cxa_atexit` in
CMake, even thou their call order is different than on other platforms.
Enable QT_FEATURE_broken_threadlocal_dtors for VxWorks by failing
compilation of cxa_thread_atexit* tests, which fixes the crashes on
VxWorks.
Task-number: QTBUG-115777
Change-Id: I4109b66903333a94301afe7fe5634ac4365a70b4
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2024-10-31 10:08:59 +00:00
|
|
|
#if defined(__vxworks) || defined(__VXWORKS__)
|
|
|
|
/*
|
|
|
|
* In VxWorks pthread implementation, when thread is finishing it calls pthread_exit(), which:
|
|
|
|
* - calls pthread cleanup procedure
|
|
|
|
* - clears pthread data (setting current thread to null)
|
|
|
|
* - calls `taskExit` VxWorks system procedure
|
|
|
|
* `taskExit` procedure calls thread_local object destructors, which if call directly or indirectly
|
|
|
|
* `pthread_self()`, terminate with error, due to not being able to obtain pthread entity.
|
|
|
|
* Thus, we need to treat VxWorks pthread implementation as `broken` in terms of thread_local variables.
|
|
|
|
*/
|
|
|
|
# error "VxWorks threadlocal destructors are called after pthread data is destroyed, causing crash."
|
|
|
|
#endif
|
|
|
|
|
QThread/Unix: refactor to split QThreadPrivate::finish() in two phases
Commit 1ed0dd88a32cd2c5ae100b48e14ff55bcbb652e6 moved the finish()
functionality from immediately after run() returns to the time of
thread-local destruction, to make sure that user destructors didn't run
after our cleaning up. But as a side effect, it made other user code run
too late, after some thread-local statics had been destroyed.
This is a common practice, which causes the destructor for worker to run
too late:
worker->moveToThread(thread);
...
QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
QObject::connect(thread, &QThread::finished, worker, &QObject::deleteLater);
This commit splits the cleanup in two phases: QThreadPrivate::finish(),
which runs immediately after run() and will call back out to user code
(finished() signal and delivery of deleteLater()), and cleanup() that
cleans up the QThread{Private,Data} state and destroys the event
dispatcher. That destruction is the only call out to user code.
I've removed the complex mix of pre-C++11 pthread_setspecific() content
and C++11 thread_local variables in favor of using one or the other, not
both. We prefer the thread-local for future-proofing and simplicity, on
platforms where we can verify this C++11 feature works, and because it
allows us to clean up QThreadData and the event dispatcher as late as
possible. (There's some code that runs even later, such as pthread TLS
destructors, used by Glib's GMainLoop)
Unfortunately, we can't use it everywhere. The commit above had already
noticed QNX has a problem and recent bug reports have shown other
platforms (Solaris, MUSL libc) that, 13 years after the ratification of
the standard, still have broken support, so we use pthread for them and
we call cleanup() from within finish() (that is, no late cleaning-up,
retaining the status quo from Qt 4 and 5). See QTBUG-129846 for an
analysis.
Drive-by moving the resetting of thread priority to after finished() is
emitted.
[ChangeLog][QtCore][QThread] Restored the Qt 6.7 timing of when the
finished() signal is emitted relative to the destruction of thread_local
variables. Qt 6.8.0 contained a change that moved this signal to a later
time on most Unix systems, which has caused problems with the order in
which those variables were accessed. The destruction of the event
dispatcher is kept at this late stage, wherever possible.
Fixes: QTBUG-129927
Fixes: QTBUG-129846
Fixes: QTBUG-130341
Task-number: QTBUG-117996
Pick-to: 6.8
Change-Id: Ie5e40dd18faa05d8f777fffdf7dc30fc4fe0c7e9
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2024-10-15 16:17:39 +00:00
|
|
|
typedef void (*dtor_func) (void *);
|
|
|
|
int TEST_FUNC(dtor_func func, void *obj, void *dso_symbol);
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
return TEST_FUNC(NULL, NULL, NULL);
|
|
|
|
}
|