diff --git a/glib/gvarianttypeinfo.c b/glib/gvarianttypeinfo.c index ca4e96de6..02aadb5a0 100644 --- a/glib/gvarianttypeinfo.c +++ b/glib/gvarianttypeinfo.c @@ -740,6 +740,36 @@ g_variant_type_info_member_info (GVariantTypeInfo *info, /* == new/ref/unref == */ static GRecMutex g_variant_type_info_lock; static GHashTable *g_variant_type_info_table; +static GPtrArray *g_variant_type_info_gc; + +#define GC_THRESHOLD 32 + +static void +gc_while_locked (void) +{ + while (g_variant_type_info_gc->len > 0) + { + GVariantTypeInfo *info = g_ptr_array_steal_index_fast (g_variant_type_info_gc, 0); + ContainerInfo *container = (ContainerInfo *)info; + + if (g_atomic_ref_count_dec (&container->ref_count)) + { + TRACE(GLIB_VARIANT_TYPE_INFO_FREE(info)); + + g_hash_table_remove (g_variant_type_info_table, + container->type_string); + + g_free (container->type_string); + + if (info->container_class == GV_ARRAY_INFO_CLASS) + array_info_free (info); + else if (info->container_class == GV_TUPLE_INFO_CLASS) + tuple_info_free (info); + else + g_assert_not_reached (); + } + } +} /* < private > * g_variant_type_info_get: @@ -864,36 +894,33 @@ g_variant_type_info_unref (GVariantTypeInfo *info) g_rec_mutex_lock (&g_variant_type_info_lock); if (g_atomic_ref_count_dec (&container->ref_count)) { + if (g_variant_type_info_gc == NULL) + g_variant_type_info_gc = g_ptr_array_new (); - TRACE(GLIB_VARIANT_TYPE_INFO_FREE(info)); + /* Steal this instance and place it onto the GC queue. + * We may bring it back to life before the next GC. + */ + g_atomic_ref_count_init (&container->ref_count); + g_ptr_array_add (g_variant_type_info_gc, info); - g_hash_table_remove (g_variant_type_info_table, - container->type_string); - if (g_hash_table_size (g_variant_type_info_table) == 0) - { - g_hash_table_unref (g_variant_type_info_table); - g_variant_type_info_table = NULL; - } - g_rec_mutex_unlock (&g_variant_type_info_lock); - - g_free (container->type_string); - - if (info->container_class == GV_ARRAY_INFO_CLASS) - array_info_free (info); - - else if (info->container_class == GV_TUPLE_INFO_CLASS) - tuple_info_free (info); - - else - g_assert_not_reached (); + if (g_variant_type_info_gc->len > GC_THRESHOLD) + gc_while_locked (); } - else - g_rec_mutex_unlock (&g_variant_type_info_lock); + g_rec_mutex_unlock (&g_variant_type_info_lock); } } void g_variant_type_info_assert_no_infos (void) { - g_assert (g_variant_type_info_table == NULL); + G_GNUC_UNUSED gboolean empty; + + g_rec_mutex_lock (&g_variant_type_info_lock); + if (g_variant_type_info_table != NULL) + gc_while_locked (); + empty = (g_variant_type_info_table == NULL || + g_hash_table_size (g_variant_type_info_table) == 0); + g_rec_mutex_unlock (&g_variant_type_info_lock); + + g_assert (empty); }