diff --git a/src/kernel/ntqthread.h b/src/kernel/ntqthread.h index 695a61fb..0b38e5a3 100644 --- a/src/kernel/ntqthread.h +++ b/src/kernel/ntqthread.h @@ -120,6 +120,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;