diff --git a/ChangeLog b/ChangeLog index cb1a1ed9d..18f68fcb0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Tue Jul 10 12:24:35 2007 Tim Janik + + * glib/gthread.[hc]: implemented g_once_init_enter(), + g_once_init_enter_impl() and g_once_init_leave(), based on a patch by + Antoine Tremblay, fixes #65041. + adapted exported inline function mechanism from gutils.[hc] for inlining + g_once_init_enter_impl() in gthread.[hc]. + 2007-07-09 Matthias Clasen * NEWS: Updates diff --git a/glib/glib.symbols b/glib/glib.symbols index 5434e2487..5ab58539f 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -1172,7 +1172,10 @@ g_str_hash #if IN_HEADER(__G_THREAD_H__) #if IN_FILE(__G_THREAD_C__) g_once_impl +g_once_init_enter_impl +g_once_init_leave #ifdef INCLUDE_INTERNAL_SYMBOLS +g_once_init_enter g_thread_init_glib #endif #ifdef INCLUDE_VARIABLES diff --git a/glib/gthread.c b/glib/gthread.c index c47a1b32b..e040524f9 100644 --- a/glib/gthread.c +++ b/glib/gthread.c @@ -32,6 +32,10 @@ * MT safe */ +/* implement gthread.h's inline functions */ +#define G_IMPLEMENT_INLINES 1 +#define __G_THREAD_C__ + #include "config.h" #include "glib.h" @@ -121,6 +125,7 @@ static GCond *g_once_cond = NULL; static GPrivate *g_thread_specific_private = NULL; static GRealThread *g_thread_all_threads = NULL; static GSList *g_thread_free_indeces = NULL; +static GSList* g_once_init_list = NULL; G_LOCK_DEFINE_STATIC (g_thread); @@ -194,6 +199,41 @@ g_once_impl (GOnce *once, return once->retval; } +gboolean +g_once_init_enter_impl (volatile gsize *value_location) +{ + gboolean need_init; + g_mutex_lock (g_once_mutex); + if (!g_once_init_list || !g_slist_find (g_once_init_list, (void*) value_location)) + { + 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; + } + g_mutex_unlock (g_once_mutex); + return need_init; +} + +void +g_once_init_leave (volatile gsize *value_location, + gsize initialization_value) +{ + g_return_if_fail (g_atomic_pointer_get (value_location) == 0); + g_return_if_fail (initialization_value != 0); + g_return_if_fail (g_once_init_list != NULL); + + g_atomic_pointer_set (value_location, initialization_value); + g_mutex_lock (g_once_mutex); + g_once_init_list = g_slist_remove (g_once_init_list, (void*) value_location); + g_cond_broadcast (g_once_cond); + g_mutex_unlock (g_once_mutex); +} + void g_static_mutex_init (GStaticMutex *mutex) { diff --git a/glib/gthread.h b/glib/gthread.h index 79099f173..2076185e3 100644 --- a/glib/gthread.h +++ b/glib/gthread.h @@ -29,7 +29,8 @@ #include #include -#include /* for g_atomic_pointer_get */ +#include /* for G_INLINE_FUNC */ +#include /* for g_atomic_pointer_get */ G_BEGIN_DECLS @@ -321,7 +322,23 @@ gpointer g_once_impl (GOnce *once, GThreadFunc func, gpointer arg); (once)->retval : \ g_once_impl ((once), (func), (arg))) #endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ - + +/* initialize-once guards, keyed by value_location */ +G_INLINE_FUNC gboolean g_once_init_enter (volatile gsize *value_location); +gboolean g_once_init_enter_impl (volatile gsize *value_location); +void g_once_init_leave (volatile gsize *value_location, + gsize initialization_value); +#if defined (G_CAN_INLINE) || defined (__G_THREAD_C__) +G_INLINE_FUNC gboolean +g_once_init_enter (volatile gsize *value_location) +{ + if G_LIKELY (g_atomic_pointer_get (value_location) !=0) + return FALSE; + else + return g_once_init_enter_impl (value_location); +} +#endif /* G_CAN_INLINE || __G_THREAD_C__ */ + /* these are some convenience macros that expand to nothing if GLib * was configured with --disable-threads. for using StaticMutexes, * you define them with G_LOCK_DEFINE_STATIC (name) or G_LOCK_DEFINE (name)