diff options
author | Tim Janik <timj@imendio.com> | 2007-08-14 00:05:52 +0000 |
---|---|---|
committer | Tim Janik <timj@src.gnome.org> | 2007-08-14 00:05:52 +0000 |
commit | d5c437081366ba9617c9a23a09d167aede52a8b9 (patch) | |
tree | 902d15f49200c90cb1e64adbb874efae80b5eaae /glib | |
parent | db68b8efa9b6aff53a640d82a0bf7ed6f819c4f0 (diff) | |
download | glib-d5c437081366ba9617c9a23a09d167aede52a8b9.tar.gz |
prevent race covered by g_once_init_enter(), by checking for previous
Tue Aug 14 02:06:10 2007 Tim Janik <timj@imendio.com>
* glib/gthread.c (g_once_init_enter_impl): prevent race covered
by g_once_init_enter(), by checking for previous initializations
before entering initialisation branch.
* tests/onceinit.c: added multi-thread/multi-initializer stress test
using unoptimized g_once_init_enter_impl().
svn path=/trunk/; revision=5701
Diffstat (limited to 'glib')
-rw-r--r-- | glib/gthread.c | 21 | ||||
-rw-r--r-- | glib/gthread.h | 2 |
2 files changed, 12 insertions, 11 deletions
diff --git a/glib/gthread.c b/glib/gthread.c index 5468e596f..fdff396ea 100644 --- a/glib/gthread.c +++ b/glib/gthread.c @@ -202,18 +202,19 @@ g_once_impl (GOnce *once, gboolean g_once_init_enter_impl (volatile gsize *value_location) { - gboolean need_init; + gboolean need_init = FALSE; g_mutex_lock (g_once_mutex); - if (!g_once_init_list || !g_slist_find (g_once_init_list, (void*) value_location)) + if (g_atomic_pointer_get ((void**) value_location) == 0) { - g_once_init_list = g_slist_prepend (g_once_init_list, (void*) value_location); - need_init = TRUE; - } - else - { - while (g_slist_find (g_once_init_list, (void*) value_location)) - g_cond_wait (g_once_cond, g_once_mutex); - need_init = FALSE; + if (!g_slist_find (g_once_init_list, (void*) value_location)) + { + need_init = TRUE; + g_once_init_list = g_slist_prepend (g_once_init_list, (void*) value_location); + } + else + do + g_cond_wait (g_once_cond, g_once_mutex); + while (g_slist_find (g_once_init_list, (void*) value_location)); } g_mutex_unlock (g_once_mutex); return need_init; diff --git a/glib/gthread.h b/glib/gthread.h index 3aaf14ecb..ea801fb76 100644 --- a/glib/gthread.h +++ b/glib/gthread.h @@ -332,7 +332,7 @@ void g_once_init_leave (volatile gsize *value_location, G_INLINE_FUNC gboolean g_once_init_enter (volatile gsize *value_location) { - if G_LIKELY (g_atomic_pointer_get ((void**) value_location) !=0) + if G_LIKELY (g_atomic_pointer_get ((void**) value_location) != 0) return FALSE; else return g_once_init_enter_impl (value_location); |