mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-24 14:36:13 +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_init_enter
|
||||
g_once_init_leave
|
||||
g_once_init_enter_pointer
|
||||
g_once_init_leave_pointer
|
||||
|
||||
<SUBSECTION>
|
||||
g_bit_lock
|
||||
|
@ -87,7 +87,8 @@
|
||||
* for condition variables to allow synchronization of threads (#GCond).
|
||||
* There are primitives for thread-private data - data that every
|
||||
* 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).
|
||||
*
|
||||
* The GLib threading system used to be initialized with g_thread_init().
|
||||
@ -719,6 +720,54 @@ gboolean
|
||||
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:
|
||||
* @location: (not nullable): location of a static initializable variable
|
||||
@ -755,6 +804,42 @@ void
|
||||
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 -------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
|
@ -236,6 +236,12 @@ GLIB_AVAILABLE_IN_ALL
|
||||
void g_once_init_leave (volatile void *location,
|
||||
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
|
||||
* they are not available, fall back to using a mutex and condition variable in
|
||||
* g_once_impl().
|
||||
@ -268,11 +274,30 @@ void g_once_init_leave (volatile void *location,
|
||||
0 ? (void) (*(location) = (result)) : (void) 0; \
|
||||
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
|
||||
# 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)))
|
||||
# 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
|
||||
|
||||
GLIB_AVAILABLE_IN_2_36
|
||||
|
Loading…
Reference in New Issue
Block a user