mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 07:26:15 +01:00
gthread: introduce g_once_init_{enter,leave}_pointer
These functions can be used to initalize pointer-type variables rather than a gsize. This is required to support CHERI-enabled platforms where gsize cannot be used to store pointers. Follow-up changes will migrate the uses of g_once_init that store pointers to the new API Helps: https://gitlab.gnome.org/GNOME/glib/-/issues/2842
This commit is contained in:
parent
9c81ff46a2
commit
726eca7c89
@ -782,6 +782,8 @@ G_ONCE_INIT
|
|||||||
g_once
|
g_once
|
||||||
g_once_init_enter
|
g_once_init_enter
|
||||||
g_once_init_leave
|
g_once_init_leave
|
||||||
|
g_once_init_enter_pointer
|
||||||
|
g_once_init_leave_pointer
|
||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
g_bit_lock
|
g_bit_lock
|
||||||
|
@ -87,7 +87,8 @@
|
|||||||
* for condition variables to allow synchronization of threads (#GCond).
|
* for condition variables to allow synchronization of threads (#GCond).
|
||||||
* There are primitives for thread-private data - data that every
|
* There are primitives for thread-private data - data that every
|
||||||
* thread has a private instance of (#GPrivate). There are facilities
|
* thread has a private instance of (#GPrivate). There are facilities
|
||||||
* for one-time initialization (#GOnce, g_once_init_enter()). Finally,
|
* for one-time initialization (#GOnce, g_once_init_enter_pointer(),
|
||||||
|
* g_once_init_enter()). Finally,
|
||||||
* there are primitives to create and manage threads (#GThread).
|
* there are primitives to create and manage threads (#GThread).
|
||||||
*
|
*
|
||||||
* The GLib threading system used to be initialized with g_thread_init().
|
* The GLib threading system used to be initialized with g_thread_init().
|
||||||
@ -719,6 +720,54 @@ gboolean
|
|||||||
return need_init;
|
return need_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_once_init_enter_pointer:
|
||||||
|
* @location: (not nullable): location of a static initializable variable
|
||||||
|
* containing `NULL`
|
||||||
|
*
|
||||||
|
* This functions behaves in the same way as g_once_init_enter(), but can
|
||||||
|
* can be used to initialize pointers (or #guintptr) instead of #gsize.
|
||||||
|
*
|
||||||
|
* |[<!-- language="C" -->
|
||||||
|
* static MyStruct *interesting_struct = NULL;
|
||||||
|
*
|
||||||
|
* if (g_once_init_enter_pointer (&interesting_struct))
|
||||||
|
* {
|
||||||
|
* MyStruct *setup_value = allocate_my_struct (); // initialization code here
|
||||||
|
*
|
||||||
|
* g_once_init_leave_pointer (&interesting_struct, g_steal_pointer (&setup_value));
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // use interesting_struct here
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the initialization section should be entered,
|
||||||
|
* %FALSE and blocks otherwise
|
||||||
|
*
|
||||||
|
* Since: 2.80
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
(g_once_init_enter_pointer) (gpointer location)
|
||||||
|
{
|
||||||
|
gpointer *value_location = (gpointer *) location;
|
||||||
|
gboolean need_init = FALSE;
|
||||||
|
g_mutex_lock (&g_once_mutex);
|
||||||
|
if (g_atomic_pointer_get (value_location) == 0)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* g_once_init_leave:
|
* g_once_init_leave:
|
||||||
* @location: (not nullable): location of a static initializable variable
|
* @location: (not nullable): location of a static initializable variable
|
||||||
@ -755,6 +804,42 @@ void
|
|||||||
g_mutex_unlock (&g_once_mutex);
|
g_mutex_unlock (&g_once_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_once_init_leave_pointer:
|
||||||
|
* @location: (not nullable): location of a static initializable variable
|
||||||
|
* containing `NULL`
|
||||||
|
* @result: new non-`NULL` value for `*location`
|
||||||
|
*
|
||||||
|
* Counterpart to g_once_init_enter_pointer(). Expects a location of a static
|
||||||
|
* `NULL`-initialized initialization variable, and an initialization value
|
||||||
|
* other than `NULL`. Sets the variable to the initialization value, and
|
||||||
|
* releases concurrent threads blocking in g_once_init_enter_pointer() on this
|
||||||
|
* initialization variable.
|
||||||
|
*
|
||||||
|
* This functions behaves in the same way as g_once_init_leave(), but
|
||||||
|
* can be used to initialize pointers (or #guintptr) instead of #gsize.
|
||||||
|
*
|
||||||
|
* Since: 2.80
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
(g_once_init_leave_pointer) (gpointer location,
|
||||||
|
gpointer result)
|
||||||
|
{
|
||||||
|
gpointer *value_location = (gpointer *) location;
|
||||||
|
gpointer old_value;
|
||||||
|
|
||||||
|
g_return_if_fail (result != 0);
|
||||||
|
|
||||||
|
old_value = g_atomic_pointer_exchange (value_location, result);
|
||||||
|
g_return_if_fail (old_value == 0);
|
||||||
|
|
||||||
|
g_mutex_lock (&g_once_mutex);
|
||||||
|
g_return_if_fail (g_once_init_list != NULL);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/* GThread {{{1 -------------------------------------------------------- */
|
/* GThread {{{1 -------------------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -236,6 +236,12 @@ GLIB_AVAILABLE_IN_ALL
|
|||||||
void g_once_init_leave (volatile void *location,
|
void g_once_init_leave (volatile void *location,
|
||||||
gsize result);
|
gsize result);
|
||||||
|
|
||||||
|
GLIB_AVAILABLE_IN_2_80
|
||||||
|
gboolean g_once_init_enter_pointer (void *location);
|
||||||
|
GLIB_AVAILABLE_IN_2_80
|
||||||
|
void g_once_init_leave_pointer (void *location,
|
||||||
|
gpointer result);
|
||||||
|
|
||||||
/* Use C11-style atomic extensions to check the fast path for status=ready. If
|
/* Use C11-style atomic extensions to check the fast path for status=ready. If
|
||||||
* they are not available, fall back to using a mutex and condition variable in
|
* they are not available, fall back to using a mutex and condition variable in
|
||||||
* g_once_impl().
|
* g_once_impl().
|
||||||
@ -268,11 +274,30 @@ void g_once_init_leave (volatile void *location,
|
|||||||
0 ? (void) (*(location) = (result)) : (void) 0; \
|
0 ? (void) (*(location) = (result)) : (void) 0; \
|
||||||
g_once_init_leave ((location), (gsize) (result)); \
|
g_once_init_leave ((location), (gsize) (result)); \
|
||||||
}))
|
}))
|
||||||
|
# define g_once_init_enter_pointer(location) \
|
||||||
|
(G_GNUC_EXTENSION ({ \
|
||||||
|
G_STATIC_ASSERT (sizeof *(location) == sizeof (gpointer)); \
|
||||||
|
(void) (0 ? (gpointer) * (location) : NULL); \
|
||||||
|
(!g_atomic_pointer_get (location) && \
|
||||||
|
g_once_init_enter_pointer (location)); \
|
||||||
|
})) GLIB_AVAILABLE_MACRO_IN_2_80
|
||||||
|
# define g_once_init_leave_pointer(location, result) \
|
||||||
|
(G_GNUC_EXTENSION ({ \
|
||||||
|
G_STATIC_ASSERT (sizeof *(location) == sizeof (gpointer)); \
|
||||||
|
0 ? (void) (*(location) = (result)) : (void) 0; \
|
||||||
|
g_once_init_leave_pointer ((location), (gpointer) (guintptr) (result)); \
|
||||||
|
})) GLIB_AVAILABLE_MACRO_IN_2_80
|
||||||
#else
|
#else
|
||||||
# define g_once_init_enter(location) \
|
# define g_once_init_enter(location) \
|
||||||
(g_once_init_enter((location)))
|
(g_once_init_enter((location)))
|
||||||
# define g_once_init_leave(location, result) \
|
# define g_once_init_leave(location, result) \
|
||||||
(g_once_init_leave((location), (gsize) (result)))
|
(g_once_init_leave((location), (gsize) (result)))
|
||||||
|
# define g_once_init_enter_pointer(location) \
|
||||||
|
(g_once_init_enter_pointer((location))) \
|
||||||
|
GLIB_AVAILABLE_MACRO_IN_2_80
|
||||||
|
# define g_once_init_leave_pointer(location, result) \
|
||||||
|
(g_once_init_leave_pointer((location), (gpointer) (guintptr) (result))) \
|
||||||
|
GLIB_AVAILABLE_MACRO_IN_2_80
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GLIB_AVAILABLE_IN_2_36
|
GLIB_AVAILABLE_IN_2_36
|
||||||
|
Loading…
Reference in New Issue
Block a user