From 89fb443ba7a6c55e43bbb46c10c7963ed3b03ad4 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 24 May 2011 16:02:33 +0100 Subject: [PATCH] g_static_private_free: defer non-trivial destruction til after we unlock Bug: https://bugzilla.gnome.org/show_bug.cgi?id=642026 Bug-NB: NB#257512 --- glib/gthread.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/glib/gthread.c b/glib/gthread.c index bf90f2a41..d2175d594 100644 --- a/glib/gthread.c +++ b/glib/gthread.c @@ -1762,6 +1762,7 @@ g_static_private_free (GStaticPrivate *private_key) { guint idx = private_key->index; GRealThread *thread; + GArray *garbage = NULL; if (!idx) return; @@ -1789,15 +1790,39 @@ g_static_private_free (GStaticPrivate *private_key) if (ddestroy) { - G_UNLOCK (g_thread); - ddestroy (ddata); - G_LOCK (g_thread); + /* defer non-trivial destruction til after we've finished + * iterating, since we must continue to hold the lock */ + if (garbage == NULL) + garbage = g_array_new (FALSE, TRUE, + sizeof (GStaticPrivateNode)); + + g_array_set_size (garbage, garbage->len + 1); + + node = &g_array_index (garbage, GStaticPrivateNode, + garbage->len - 1); + node->data = ddata; + node->destroy = ddestroy; } } } g_thread_free_indeces = g_slist_prepend (g_thread_free_indeces, GUINT_TO_POINTER (idx)); G_UNLOCK (g_thread); + + if (garbage) + { + guint i; + + for (i = 0; i < garbage->len; i++) + { + GStaticPrivateNode *node; + + node = &g_array_index (garbage, GStaticPrivateNode, i); + node->destroy (node->data); + } + + g_array_free (garbage, TRUE); + } } /* GThread Extra Functions {{{1 ------------------------------------------- */