Make quark to string lockless

We do this by assigning to g_quarks atomically and leaking it when
replacing it atomically. Then its safe to consume the array
on the reader side (atomically).

Also, since we're leaking quarks on growing, bump the block size
so that we're not leaking as much. gtk3-demo allocates > 1500 quarks,
and gnome apps > 3000. I'm setting the block to 2048 which means no
leaks for small gtk3 apps and just one leak for gnome apps.

https://bugzilla.gnome.org/show_bug.cgi?id=650458
This commit is contained in:
Alexander Larsson 2011-05-19 21:30:38 +02:00 committed by Matthias Clasen
parent 3f8638ce93
commit 7ae5e9c248

View File

@ -136,7 +136,7 @@
**/
/* --- defines --- */
#define G_QUARK_BLOCK_SIZE (512)
#define G_QUARK_BLOCK_SIZE (2048)
#define G_DATALIST_FLAGS_MASK_INTERNAL 0x7
@ -207,7 +207,7 @@ static GDataset *g_dataset_cached = NULL; /* should this be
G_LOCK_DEFINE_STATIC (g_quark_global);
static GHashTable *g_quark_ht = NULL;
static gchar **g_quarks = NULL;
static GQuark g_quark_seq_id = 0;
static int g_quark_seq_id = 0;
/* --- functions --- */
@ -1217,11 +1217,14 @@ G_CONST_RETURN gchar*
g_quark_to_string (GQuark quark)
{
gchar* result = NULL;
gchar **quarks;
gint quark_seq_id;
G_LOCK (g_quark_global);
if (quark < g_quark_seq_id)
result = g_quarks[quark];
G_UNLOCK (g_quark_global);
quark_seq_id = g_atomic_int_get (&g_quark_seq_id);
quarks = g_atomic_pointer_get (&g_quarks);
if (quark < quark_seq_id)
result = quarks[quark];
return result;
}
@ -1231,20 +1234,32 @@ static inline GQuark
g_quark_new (gchar *string)
{
GQuark quark;
gchar **g_quarks_new;
if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
{
g_quarks_new = g_new (gchar*, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
if (g_quark_seq_id != 0)
memcpy (g_quarks_new, g_quarks, sizeof (char *) * g_quark_seq_id);
memset (g_quarks_new + g_quark_seq_id, 0, sizeof (char *) * G_QUARK_BLOCK_SIZE);
/* This leaks the old quarks array. Its unfortunate, but it allows
us to do lockless lookup of the arrays, and there shouldn't be that
many quarks in an app */
g_atomic_pointer_set (&g_quarks, g_quarks_new);
}
if (!g_quark_ht)
{
g_assert (g_quark_seq_id == 0);
g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
g_quarks[g_quark_seq_id++] = NULL;
g_quarks[g_quark_seq_id] = NULL;
g_atomic_int_inc (&g_quark_seq_id);
}
quark = g_quark_seq_id++;
g_quarks[quark] = string;
quark = g_quark_seq_id;
g_atomic_pointer_set (&g_quarks[quark], string);
g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
g_atomic_int_inc (&g_quark_seq_id);
return quark;
}