From f1512917e6e46e30000bcca2ebf06ef9d15b751d Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Tue, 4 Oct 2011 16:08:27 -0400 Subject: [PATCH] win32: stop leaking GPrivate data Instead of running the GPrivate destructors from our thread proxy code, run it from the DllMain handler for the DLL_THREAD_DETACH case. This should ensure that thread-local data is free at the exit of all threads -- not just the ones we created for ourselves. https://bugzilla.gnome.org/show_bug.cgi?id=660745 --- glib/glib-init.c | 4 +++ glib/glib-init.h | 1 + glib/gthread-win32.c | 95 +++++++++++++++++++++++++++------------------------- 3 files changed, 54 insertions(+), 46 deletions(-) diff --git a/glib/glib-init.c b/glib/glib-init.c index ffc3a2f..4879e0b 100644 --- a/glib/glib-init.c +++ b/glib/glib-init.c @@ -225,6 +225,10 @@ DllMain (HINSTANCE hinstDLL, glib_init (); break; + case DLL_THREAD_DETACH: + g_thread_win32_thread_detach (); + break; + default: /* do nothing */ ; diff --git a/glib/glib-init.h b/glib/glib-init.h index f7b6f0b..79b6c26 100644 --- a/glib/glib-init.h +++ b/glib/glib-init.h @@ -31,6 +31,7 @@ GLIB_VAR gboolean g_mem_gc_friendly; #ifdef G_OS_WIN32 #include +G_GNUC_INTERNAL void g_thread_win32_thread_detach (void); G_GNUC_INTERNAL void g_thread_win32_init (void); G_GNUC_INTERNAL extern HMODULE glib_dll; #endif diff --git a/glib/gthread-win32.c b/glib/gthread-win32.c index 8607431..245a4fb 100644 --- a/glib/gthread-win32.c +++ b/glib/gthread-win32.c @@ -489,51 +489,6 @@ g_system_thread_self (gpointer thread) void g_system_thread_exit (void) { - GThreadData *self = TlsGetValue (g_thread_self_tls); - gboolean dtors_called; - - do - { - GPrivateDestructor *dtor; - - /* We go by the POSIX book on this one. - * - * If we call a destructor then there is a chance that some new - * TLS variables got set by code called in that destructor. - * - * Loop until nothing is left. - */ - dtors_called = FALSE; - - for (dtor = g_private_destructors; dtor; dtor = dtor->next) - { - gpointer value; - - value = TlsGetValue (dtor->index); - if (value != NULL && dtor->notify != NULL) - { - /* POSIX says to clear this before the call */ - TlsSetValue (dtor->index, NULL); - dtor->notify (value); - dtors_called = TRUE; - } - } - } - while (dtors_called); - - if (self) - { - if (!self->joinable) - { - win32_check_for_error (CloseHandle (self->thread)); - g_free (self); - } - win32_check_for_error (TlsSetValue (g_thread_self_tls, NULL)); - } - - if (g_thread_impl_vtable.CallThisOnThreadExit) - g_thread_impl_vtable.CallThisOnThreadExit (); - _endthreadex (0); } @@ -1085,5 +1040,53 @@ g_thread_win32_init (void) InitializeCriticalSection (&g_private_lock); } -/* vim:set foldmethod=marker: */ +G_GNUC_INTERNAL void +g_thread_win32_thread_detach (void) +{ + GThreadData *self = TlsGetValue (g_thread_self_tls); + gboolean dtors_called; + + do + { + GPrivateDestructor *dtor; + + /* We go by the POSIX book on this one. + * + * If we call a destructor then there is a chance that some new + * TLS variables got set by code called in that destructor. + * + * Loop until nothing is left. + */ + dtors_called = FALSE; + + for (dtor = g_private_destructors; dtor; dtor = dtor->next) + { + gpointer value; + + value = TlsGetValue (dtor->index); + if (value != NULL && dtor->notify != NULL) + { + /* POSIX says to clear this before the call */ + TlsSetValue (dtor->index, NULL); + dtor->notify (value); + dtors_called = TRUE; + } + } + } + while (dtors_called); + + if (self) + { + if (!self->joinable) + { + win32_check_for_error (CloseHandle (self->thread)); + g_free (self); + } + win32_check_for_error (TlsSetValue (g_thread_self_tls, NULL)); + } + if (g_thread_impl_vtable.CallThisOnThreadExit) + g_thread_impl_vtable.CallThisOnThreadExit (); +} + +/* vim:set foldmethod=marker: */ -- 2.7.4