Refactor GStaticPrivate accessors to facilitate protecting them with locks

* g_static_private_get: have a single entry and exit

* g_static_private_set: delay creation of GArray so the whole tail of
  the function can be under the private_data lock without risking
  deadlock with the g_thread lock; call the destructor last, after
  we could have unlocked

* g_static_private_free: choose next thread in list before accessing
  private_data, to keep all accesses together

* g_thread_cleanup: steal private_data first, then work exclusively with
  the stolen array (which doesn't need to be under a lock any more)

Bug: https://bugzilla.gnome.org/show_bug.cgi?id=642026
Bug-NB: NB#257512
This commit is contained in:
Simon McVittie 2011-05-24 16:23:02 +01:00 committed by Matthias Clasen
parent b05f0b351c
commit 83f1b12388

View File

@ -1653,18 +1653,15 @@ g_static_private_get (GStaticPrivate *private_key)
{ {
GRealThread *self = (GRealThread*) g_thread_self (); GRealThread *self = (GRealThread*) g_thread_self ();
GArray *array; GArray *array;
gpointer ret = NULL;
array = self->private_data; array = self->private_data;
if (!array)
return NULL;
if (!private_key->index) if (array && private_key->index != 0 && private_key->index <= array->len)
return NULL; ret = g_array_index (array, GStaticPrivateNode,
else if (private_key->index <= array->len)
return g_array_index (array, GStaticPrivateNode,
private_key->index - 1).data; private_key->index - 1).data;
else
return NULL; return ret;
} }
/** /**
@ -1696,13 +1693,8 @@ g_static_private_set (GStaticPrivate *private_key,
GArray *array; GArray *array;
static guint next_index = 0; static guint next_index = 0;
GStaticPrivateNode *node; GStaticPrivateNode *node;
gpointer ddata = NULL;
array = self->private_data; GDestroyNotify ddestroy = NULL;
if (!array)
{
array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
self->private_data = array;
}
if (!private_key->index) if (!private_key->index)
{ {
@ -1725,25 +1717,26 @@ g_static_private_set (GStaticPrivate *private_key,
G_UNLOCK (g_thread); G_UNLOCK (g_thread);
} }
array = self->private_data;
if (!array)
{
array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
self->private_data = array;
}
if (private_key->index > array->len) if (private_key->index > array->len)
g_array_set_size (array, private_key->index); g_array_set_size (array, private_key->index);
node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1); node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
if (node->destroy)
{ ddata = node->data;
gpointer ddata = node->data; ddestroy = node->destroy;
GDestroyNotify ddestroy = node->destroy;
node->data = data; node->data = data;
node->destroy = notify; node->destroy = notify;
if (ddestroy)
ddestroy (ddata); ddestroy (ddata);
}
else
{
node->data = data;
node->destroy = notify;
}
} }
/** /**
@ -1761,7 +1754,7 @@ void
g_static_private_free (GStaticPrivate *private_key) g_static_private_free (GStaticPrivate *private_key)
{ {
guint idx = private_key->index; guint idx = private_key->index;
GRealThread *thread; GRealThread *thread, *next;
GArray *garbage = NULL; GArray *garbage = NULL;
if (!idx) if (!idx)
@ -1772,10 +1765,14 @@ g_static_private_free (GStaticPrivate *private_key)
G_LOCK (g_thread); G_LOCK (g_thread);
thread = g_thread_all_threads; thread = g_thread_all_threads;
while (thread)
for (thread = g_thread_all_threads; thread; thread = next)
{ {
GArray *array = thread->private_data; GArray *array;
thread = thread->next;
next = thread->next;
array = thread->private_data;
if (array && idx <= array->len) if (array && idx <= array->len)
{ {
@ -1832,9 +1829,13 @@ g_thread_cleanup (gpointer data)
if (data) if (data)
{ {
GRealThread* thread = data; GRealThread* thread = data;
if (thread->private_data) GArray *array;
array = thread->private_data;
thread->private_data = NULL;
if (array)
{ {
GArray* array = thread->private_data;
guint i; guint i;
for (i = 0; i < array->len; i++ ) for (i = 0; i < array->len; i++ )