summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Golubev <fatzer2@gmail.com>2024-03-16 08:31:50 +0300
committerMichele Calgaro <michele.calgaro@yahoo.it>2024-03-18 18:37:17 +0900
commit323382b1896ae350cf5d6b10949c647e4465b3b9 (patch)
treec33d2ceeff57a512f1210606023ba4c4f8756c10
parent336e61b2302bd34e0e80af1bb38533d4f1a912ba (diff)
downloadtqt3-323382b1896ae350cf5d6b10949c647e4465b3b9.tar.gz
tqt3-323382b1896ae350cf5d6b10949c647e4465b3b9.zip
Fix TQThreadStorage destruction in the main thread
Before that the allocations of TQThreadStorage objects from the main thread were never destroyed and memory associated with them were never freed. The second one isn't a huge problem as at that point program is terminating anyway (but it still makes valgrind complain). The first one is the bigger issue as destructors might contain some essential external cleanups like removing temporary files. Also make `TQApplication::guiThread()` return `0` when the thread is destroyed (may happen on the program exiting during destruction of statics). Signed-off-by: Alexander Golubev <fatzer2@gmail.com> (cherry picked from commit b1e6f384640525c5a0caceef017848f8ebee46b8)
-rw-r--r--src/kernel/ntqthread.h1
-rw-r--r--src/kernel/qapplication.cpp24
-rw-r--r--src/kernel/qthread_unix.cpp5
-rw-r--r--src/tools/qthreadinstance_p.h2
-rw-r--r--src/tools/qthreadstorage_unix.cpp17
5 files changed, 47 insertions, 2 deletions
diff --git a/src/kernel/ntqthread.h b/src/kernel/ntqthread.h
index 3776de41..5bace1b1 100644
--- a/src/kernel/ntqthread.h
+++ b/src/kernel/ntqthread.h
@@ -129,6 +129,7 @@ protected:
private:
TQThreadInstance * d;
friend class TQThreadInstance;
+ friend class TQThreadStorageData;
friend class TQCoreApplicationThread;
friend class TQApplication;
friend class TQEventLoop;
diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp
index fbdb9330..e8658cda 100644
--- a/src/kernel/qapplication.cpp
+++ b/src/kernel/qapplication.cpp
@@ -542,12 +542,19 @@ TQClipboard *tqt_clipboard = 0; // global clipboard object
TQWidgetList * tqt_modal_stack=0; // stack of modal widgets
#ifdef TQT_THREAD_SUPPORT
+
// thread wrapper for the main() thread
class TQCoreApplicationThread : public TQThread
{
public:
inline TQCoreApplicationThread()
{
+#ifdef QT_CHECK_STATE
+ if ( tqt_gui_thread_self )
+ tqWarning( "TQCoreApplicationThread: there should be exactly one main thread object" );
+#endif
+ tqt_gui_thread_self = this;
+
TQThreadInstance::setCurrentThread(this);
// thread should be running and not finished for the lifetime
@@ -556,11 +563,19 @@ public:
d->finished = false;
d->eventLoop = NULL;
}
+
inline ~TQCoreApplicationThread()
{
+ tqt_gui_thread_self = nullptr;
+
// avoid warning from TQThread
d->running = false;
+ // do some cleanup, namely clean up the thread-local storage associated with the GUI thread
+ TQThreadInstance::finishGuiThread(d);
}
+
+ static TQCoreApplicationThread* self() { return tqt_gui_thread_self; }
+
private:
inline void run()
{
@@ -568,10 +583,15 @@ private:
// only so that we can instantiate the object
tqFatal("TQCoreApplicationThread: internal error");
}
+
+ static TQCoreApplicationThread* tqt_gui_thread_self;
};
+TQCoreApplicationThread* TQCoreApplicationThread::tqt_gui_thread_self = nullptr;
+
+// construct exactly one instance of the core thread with static storage duration. Do it static
+// rather than in the heap as we need it to be properly destroyed on the exit from the program.
static TQCoreApplicationThread tqt_main_thread;
-static TQThread *mainThread() { return &tqt_main_thread; }
#endif
// Definitions for posted events
@@ -1035,7 +1055,7 @@ TQApplication::TQApplication(Display *dpy, int argc, char **argv,
#ifdef TQT_THREAD_SUPPORT
TQThread* TQApplication::guiThread() {
- return mainThread();
+ return TQCoreApplicationThread::self();
}
bool TQApplication::isGuiThread() {
diff --git a/src/kernel/qthread_unix.cpp b/src/kernel/qthread_unix.cpp
index 7a6bc339..6a6f81b7 100644
--- a/src/kernel/qthread_unix.cpp
+++ b/src/kernel/qthread_unix.cpp
@@ -180,6 +180,11 @@ void TQThreadInstance::finish( void * )
}
}
+void TQThreadInstance::finishGuiThread(TQThreadInstance *d) {
+ TQThreadStorageData::finish( d->thread_storage );
+ d->thread_storage = 0;
+}
+
TQMutex *TQThreadInstance::mutex() const
{
return qt_thread_mutexpool ? qt_thread_mutexpool->get( (void *) this ) : 0;
diff --git a/src/tools/qthreadinstance_p.h b/src/tools/qthreadinstance_p.h
index 14f0de59..076c2ba1 100644
--- a/src/tools/qthreadinstance_p.h
+++ b/src/tools/qthreadinstance_p.h
@@ -100,6 +100,8 @@ public:
static void finish( TQThreadInstance * );
#endif // Q_OS_WIN32
+ static void finishGuiThread( TQThreadInstance *d );
+
TQEventLoop* eventLoop;
int cleanupType;
bool disableThreadPostedEvents : 1;
diff --git a/src/tools/qthreadstorage_unix.cpp b/src/tools/qthreadstorage_unix.cpp
index d53f6fb6..86192868 100644
--- a/src/tools/qthreadstorage_unix.cpp
+++ b/src/tools/qthreadstorage_unix.cpp
@@ -38,6 +38,8 @@
#ifdef TQT_THREAD_SUPPORT
+#include "ntqapplication.h"
+#include "ntqthread.h"
#include "qplatformdefs.h"
#include "ntqthreadstorage.h"
@@ -88,6 +90,21 @@ TQThreadStorageData::TQThreadStorageData( void (*func)( void * ) )
TQThreadStorageData::~TQThreadStorageData()
{
+ // The Gui thread has static storage duration, TQThreadStorage are almost always static (it's
+ // technically possible to allocate those in the heap, but it's quite unusual). It's impossible
+ // to predict whichever of those one gets destroyed first, but usually it's a TQThreadStorage.
+ // In that case we have to do the cleanup of its storage ourself as it won't be possible after
+ // nullifying the destructor below.
+ TQThread *guiThread = TQApplication::guiThread();
+ if (guiThread) {
+ TQThreadInstance *d = guiThread->d;
+ TQMutexLocker locker( d->mutex() );
+ if (d->thread_storage && d->thread_storage[id]) {
+ thread_storage_usage[id].func( d->thread_storage[id] );
+ d->thread_storage[id] = nullptr;
+ }
+ }
+
pthread_mutex_lock( &thread_storage_mutex );
thread_storage_usage[id].used = FALSE;
thread_storage_usage[id].func = 0;