macro wrappers for g_once_init_enter/leave

Give the macro wrapper treatment to g_once_init_enter() and leave() in
the same style that we did for gatomic.

It is now possible to use these macros with any pointer-sized object,
and not just gsize.  The leave() macro ensures that the initialisation
result is a compatible type with the pointer that it is being written
to.

Just like with gatomic, there could be problems caused by use of (void*)
casts.  We'll see how that goes, and reevaluate if necessary.

https://bugzilla.gnome.org/show_bug.cgi?id=660743
This commit is contained in:
Ryan Lortie 2011-10-03 14:40:00 -04:00
parent 8f58c2c0c4
commit 794c1a30bc
5 changed files with 55 additions and 21 deletions

View File

@ -275,6 +275,13 @@ g_enumerable_thread_remove (GRealThread *thread)
G_UNLOCK (g_thread); G_UNLOCK (g_thread);
} }
/* GOnce {{{1 ------------------------------------------------------------- */
gboolean
g_once_init_enter_impl (volatile gsize *location)
{
return (g_once_init_enter) (location);
}
/* GStaticMutex {{{1 ------------------------------------------------------ */ /* GStaticMutex {{{1 ------------------------------------------------------ */
/** /**

View File

@ -198,6 +198,8 @@ void g_static_private_set (GStaticPrivate *private_key,
GDestroyNotify notify); GDestroyNotify notify);
void g_static_private_free (GStaticPrivate *private_key); void g_static_private_free (GStaticPrivate *private_key);
gboolean g_once_init_enter_impl (volatile gsize *location);
G_END_DECLS G_END_DECLS
#endif /* __G_DEPRECATED_THREAD_H__ */ #endif /* __G_DEPRECATED_THREAD_H__ */

View File

@ -753,8 +753,9 @@ g_once_impl (GOnce *once,
* Since: 2.14 * Since: 2.14
*/ */
gboolean gboolean
g_once_init_enter_impl (volatile gsize *value_location) (g_once_init_enter) (volatile void *pointer)
{ {
volatile gsize *value_location = pointer;
gboolean need_init = FALSE; gboolean need_init = FALSE;
g_mutex_lock (&g_once_mutex); g_mutex_lock (&g_once_mutex);
if (g_atomic_pointer_get (value_location) == NULL) if (g_atomic_pointer_get (value_location) == NULL)
@ -777,7 +778,7 @@ g_once_init_enter_impl (volatile gsize *value_location)
* g_once_init_leave: * g_once_init_leave:
* @value_location: location of a static initializable variable * @value_location: location of a static initializable variable
* containing 0 * containing 0
* @initialization_value: new non-0 value for *@value_location * @result: new non-0 value for *@value_location
* *
* Counterpart to g_once_init_enter(). Expects a location of a static * Counterpart to g_once_init_enter(). Expects a location of a static
* 0-initialized initialization variable, and an initialization value * 0-initialized initialization variable, and an initialization value
@ -788,14 +789,16 @@ g_once_init_enter_impl (volatile gsize *value_location)
* Since: 2.14 * Since: 2.14
*/ */
void void
g_once_init_leave (volatile gsize *value_location, (g_once_init_leave) (volatile void *pointer,
gsize initialization_value) gsize result)
{ {
volatile gsize *value_location = pointer;
g_return_if_fail (g_atomic_pointer_get (value_location) == NULL); g_return_if_fail (g_atomic_pointer_get (value_location) == NULL);
g_return_if_fail (initialization_value != 0); g_return_if_fail (result != 0);
g_return_if_fail (g_once_init_list != NULL); g_return_if_fail (g_once_init_list != NULL);
g_atomic_pointer_set (value_location, initialization_value); g_atomic_pointer_set (value_location, result);
g_mutex_lock (&g_once_mutex); g_mutex_lock (&g_once_mutex);
g_once_init_list = g_slist_remove (g_once_init_list, (void*) value_location); g_once_init_list = g_slist_remove (g_once_init_list, (void*) value_location);
g_cond_broadcast (&g_once_cond); g_cond_broadcast (&g_once_cond);

View File

@ -154,21 +154,31 @@ gpointer g_once_impl (GOnce *once, GThreadFunc func, gpointer arg);
g_once_impl ((once), (func), (arg))) g_once_impl ((once), (func), (arg)))
#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ #endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
/* initialize-once guards, keyed by value_location */ /* initialize-once guards, keyed by location */
G_INLINE_FUNC gboolean g_once_init_enter (volatile gsize *value_location); gboolean g_once_init_enter (volatile void *location);
gboolean g_once_init_enter_impl (volatile gsize *value_location); void g_once_init_leave (volatile void *location,
void g_once_init_leave (volatile gsize *value_location, gsize result);
gsize initialization_value);
#if defined (G_CAN_INLINE) || defined (__G_THREAD_C__) #ifdef __GNUC__
G_INLINE_FUNC gboolean # define g_once_init_enter(location) \
g_once_init_enter (volatile gsize *value_location) (G_GNUC_EXTENSION ({ \
{ G_STATIC_ASSERT (sizeof *(location) == sizeof (gpointer)); \
if G_LIKELY ((gpointer) g_atomic_pointer_get (value_location) != NULL) (void) (0 ? (gpointer) *(location) : 0); \
return FALSE; (!g_atomic_pointer_get (location) && \
else g_once_init_enter (location)); \
return g_once_init_enter_impl (value_location); }))
} # define g_once_init_leave(location, result) \
#endif /* G_CAN_INLINE || __G_THREAD_C__ */ (G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(location) == sizeof (gpointer)); \
(void) (0 ? *(location) = (result) : 0); \
g_once_init_leave ((location), (gsize) (result)); \
}))
#else
# define g_once_init_enter(location) \
(g_once_init_enter((location)))
# define g_once_init_leave(location, result) \
(g_once_init_leave((location), (gsize) (result)))
#endif
#define G_LOCK_NAME(name) g__ ## name ## _lock #define G_LOCK_NAME(name) g__ ## name ## _lock
#define G_LOCK_DEFINE_STATIC(name) static G_LOCK_DEFINE (name) #define G_LOCK_DEFINE_STATIC(name) static G_LOCK_DEFINE (name)

View File

@ -112,6 +112,17 @@ test_once3 (void)
g_assert_cmpint (shared, ==, 42); g_assert_cmpint (shared, ==, 42);
} }
static void
test_once4 (void)
{
static const gchar *val;
if (g_once_init_enter (&val))
g_once_init_leave (&val, "foo");
g_assert_cmpstr (val, ==, "foo");
}
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
@ -120,6 +131,7 @@ main (int argc, char *argv[])
g_test_add_func ("/thread/once1", test_once1); g_test_add_func ("/thread/once1", test_once1);
g_test_add_func ("/thread/once2", test_once2); g_test_add_func ("/thread/once2", test_once2);
g_test_add_func ("/thread/once3", test_once3); g_test_add_func ("/thread/once3", test_once3);
g_test_add_func ("/thread/once4", test_once4);
return g_test_run (); return g_test_run ();
} }