Merge branch 'wip/3v1n0/gmain-more-atomic' into 'main'

gmain: Use atomic logic to handle internal GSource flags

See merge request GNOME/glib!4488
This commit is contained in:
Philip Withnall 2025-02-19 23:27:51 +00:00
commit 3a4beabc29
3 changed files with 48 additions and 34 deletions

View File

@ -755,8 +755,11 @@ repeatedly_connecting_thread (gpointer data)
for (guint i = 0; i < iterations; ++i) for (guint i = 0; i < iterations; ++i)
{ {
gboolean callback_called = FALSE; /* (atomic) */ gboolean callback_called; /* (atomic) */
gboolean called; gboolean called;
g_atomic_int_set (&callback_called, FALSE);
gulong id = g_cancellable_connect (cancellable, gulong id = g_cancellable_connect (cancellable,
G_CALLBACK (on_racy_cancellable_cancelled), G_CALLBACK (on_racy_cancellable_cancelled),
&callback_called, NULL); &callback_called, NULL);
@ -780,13 +783,14 @@ test_cancellable_cancel_reset_connect_races (void)
GThread *resetting_thread = NULL; GThread *resetting_thread = NULL;
GThread *cancelling_thread = NULL; GThread *cancelling_thread = NULL;
GThread *connecting_thread = NULL; GThread *connecting_thread = NULL;
gboolean callback_called = FALSE; /* (atomic) */ gboolean callback_called; /* (atomic) */
g_test_summary ("Tests threads racing for cancelling, connecting and disconnecting " g_test_summary ("Tests threads racing for cancelling, connecting and disconnecting "
" and resetting a GCancellable"); " and resetting a GCancellable");
cancellable = g_cancellable_new (); cancellable = g_cancellable_new ();
g_atomic_int_set (&callback_called, FALSE);
g_cancellable_connect (cancellable, G_CALLBACK (on_racy_cancellable_cancelled), g_cancellable_connect (cancellable, G_CALLBACK (on_racy_cancellable_cancelled),
&callback_called, NULL); &callback_called, NULL);
g_assert_false (g_atomic_int_get (&callback_called)); g_assert_false (g_atomic_int_get (&callback_called));

View File

@ -32,6 +32,7 @@
*/ */
#include "config.h" #include "config.h"
#include "glib.h"
#include "glibconfig.h" #include "glibconfig.h"
#include "glib_trace.h" #include "glib_trace.h"
@ -307,8 +308,10 @@ typedef struct _GSourceIter
#define UNLOCK_CONTEXT(context) g_mutex_unlock (&context->mutex) #define UNLOCK_CONTEXT(context) g_mutex_unlock (&context->mutex)
#define G_THREAD_SELF g_thread_self () #define G_THREAD_SELF g_thread_self ()
#define SOURCE_DESTROYED(source) (((source)->flags & G_HOOK_FLAG_ACTIVE) == 0) #define SOURCE_DESTROYED(source) \
#define SOURCE_BLOCKED(source) (((source)->flags & G_SOURCE_BLOCKED) != 0) ((g_atomic_int_get (&((source)->flags)) & G_HOOK_FLAG_ACTIVE) == 0)
#define SOURCE_BLOCKED(source) \
((g_atomic_int_get (&((source)->flags)) & G_SOURCE_BLOCKED) != 0)
/* Forward declarations */ /* Forward declarations */
@ -930,11 +933,11 @@ g_source_new (GSourceFuncs *source_funcs,
source = (GSource*) g_malloc0 (struct_size); source = (GSource*) g_malloc0 (struct_size);
source->priv = g_slice_new0 (GSourcePrivate); source->priv = g_slice_new0 (GSourcePrivate);
source->source_funcs = source_funcs; source->source_funcs = source_funcs;
source->ref_count = 1; g_atomic_int_set (&source->ref_count, 1);
source->priority = G_PRIORITY_DEFAULT; source->priority = G_PRIORITY_DEFAULT;
source->flags = G_HOOK_FLAG_ACTIVE; g_atomic_int_set (&source->flags, G_HOOK_FLAG_ACTIVE);
source->priv->ready_time = -1; source->priv->ready_time = -1;
@ -976,10 +979,14 @@ void
g_source_set_dispose_function (GSource *source, g_source_set_dispose_function (GSource *source,
GSourceDisposeFunc dispose) GSourceDisposeFunc dispose)
{ {
gboolean was_unset G_GNUC_UNUSED;
g_return_if_fail (source != NULL); g_return_if_fail (source != NULL);
g_return_if_fail (source->priv->dispose == NULL);
g_return_if_fail (g_atomic_int_get (&source->ref_count) > 0); g_return_if_fail (g_atomic_int_get (&source->ref_count) > 0);
source->priv->dispose = dispose;
was_unset = g_atomic_pointer_compare_and_exchange (&source->priv->dispose,
NULL, dispose);
g_return_if_fail (was_unset);
} }
/* Holds context's lock */ /* Holds context's lock */
@ -1285,7 +1292,7 @@ g_source_destroy_internal (GSource *source,
gpointer old_cb_data; gpointer old_cb_data;
GSourceCallbackFuncs *old_cb_funcs; GSourceCallbackFuncs *old_cb_funcs;
source->flags &= ~G_HOOK_FLAG_ACTIVE; g_atomic_int_and (&source->flags, ~G_HOOK_FLAG_ACTIVE);
old_cb_data = source->callback_data; old_cb_data = source->callback_data;
old_cb_funcs = source->callback_funcs; old_cb_funcs = source->callback_funcs;
@ -1359,7 +1366,7 @@ g_source_destroy (GSource *source)
if (context) if (context)
g_source_destroy_internal (source, context, FALSE); g_source_destroy_internal (source, context, FALSE);
else else
source->flags &= ~G_HOOK_FLAG_ACTIVE; g_atomic_int_and (&source->flags, ~G_HOOK_FLAG_ACTIVE);
} }
/** /**
@ -2007,9 +2014,9 @@ g_source_set_can_recurse (GSource *source,
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
if (can_recurse) if (can_recurse)
source->flags |= G_SOURCE_CAN_RECURSE; g_atomic_int_or (&source->flags, G_SOURCE_CAN_RECURSE);
else else
source->flags &= ~G_SOURCE_CAN_RECURSE; g_atomic_int_and (&source->flags, ~G_SOURCE_CAN_RECURSE);
if (context) if (context)
UNLOCK_CONTEXT (context); UNLOCK_CONTEXT (context);
@ -2030,7 +2037,7 @@ g_source_get_can_recurse (GSource *source)
g_return_val_if_fail (source != NULL, FALSE); g_return_val_if_fail (source != NULL, FALSE);
g_return_val_if_fail (g_atomic_int_get (&source->ref_count) > 0, FALSE); g_return_val_if_fail (g_atomic_int_get (&source->ref_count) > 0, FALSE);
return (source->flags & G_SOURCE_CAN_RECURSE) != 0; return (g_atomic_int_get (&source->flags) & G_SOURCE_CAN_RECURSE) != 0;
} }
static void static void
@ -2246,11 +2253,13 @@ retry_beginning:
if (old_ref == 1) if (old_ref == 1)
{ {
/* If there's a dispose function, call this first */ /* If there's a dispose function, call this first */
if (source->priv->dispose) GSourceDisposeFunc dispose_func;
if ((dispose_func = g_atomic_pointer_get (&source->priv->dispose)))
{ {
if (context) if (context)
UNLOCK_CONTEXT (context); UNLOCK_CONTEXT (context);
source->priv->dispose (source); dispose_func (source);
if (context) if (context)
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
} }
@ -3267,7 +3276,7 @@ block_source (GSource *source)
g_return_if_fail (!SOURCE_BLOCKED (source)); g_return_if_fail (!SOURCE_BLOCKED (source));
source->flags |= G_SOURCE_BLOCKED; g_atomic_int_or (&source->flags, G_SOURCE_BLOCKED);
if (source->context) if (source->context)
{ {
@ -3302,7 +3311,7 @@ unblock_source (GSource *source)
g_return_if_fail (SOURCE_BLOCKED (source)); /* Source already unblocked */ g_return_if_fail (SOURCE_BLOCKED (source)); /* Source already unblocked */
g_return_if_fail (!SOURCE_DESTROYED (source)); g_return_if_fail (!SOURCE_DESTROYED (source));
source->flags &= ~G_SOURCE_BLOCKED; g_atomic_int_and (&source->flags, ~G_SOURCE_BLOCKED);
tmp_list = source->poll_fds; tmp_list = source->poll_fds;
while (tmp_list) while (tmp_list)
@ -3339,7 +3348,7 @@ g_main_dispatch (GMainContext *context)
context->pending_dispatches->pdata[i] = NULL; context->pending_dispatches->pdata[i] = NULL;
g_assert (source); g_assert (source);
source->flags &= ~G_SOURCE_READY; g_atomic_int_and (&source->flags, ~G_SOURCE_READY);
if (!SOURCE_DESTROYED (source)) if (!SOURCE_DESTROYED (source))
{ {
@ -3363,11 +3372,12 @@ g_main_dispatch (GMainContext *context)
if (cb_funcs) if (cb_funcs)
cb_funcs->ref (cb_data); cb_funcs->ref (cb_data);
if ((source->flags & G_SOURCE_CAN_RECURSE) == 0) if ((g_atomic_int_get (&source->flags) & G_SOURCE_CAN_RECURSE) == 0)
block_source (source); block_source (source);
was_in_call = source->flags & G_HOOK_FLAG_IN_CALL; was_in_call = g_atomic_int_or (&source->flags,
source->flags |= G_HOOK_FLAG_IN_CALL; (GSourceFlags) G_HOOK_FLAG_IN_CALL) &
G_HOOK_FLAG_IN_CALL;
if (cb_funcs) if (cb_funcs)
cb_funcs->get (cb_data, source, &callback, &user_data); cb_funcs->get (cb_data, source, &callback, &user_data);
@ -3404,7 +3414,7 @@ g_main_dispatch (GMainContext *context)
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
if (!was_in_call) if (!was_in_call)
source->flags &= ~G_HOOK_FLAG_IN_CALL; g_atomic_int_and (&source->flags, ~G_HOOK_FLAG_IN_CALL);
if (SOURCE_BLOCKED (source) && !SOURCE_DESTROYED (source)) if (SOURCE_BLOCKED (source) && !SOURCE_DESTROYED (source))
unblock_source (source); unblock_source (source);
@ -3773,7 +3783,7 @@ g_main_context_prepare_unlocked (GMainContext *context,
if ((n_ready > 0) && (source->priority > current_priority)) if ((n_ready > 0) && (source->priority > current_priority))
break; break;
if (!(source->flags & G_SOURCE_READY)) if (!(g_atomic_int_get (&source->flags) & G_SOURCE_READY))
{ {
gboolean result; gboolean result;
gboolean (* prepare) (GSource *source, gboolean (* prepare) (GSource *source,
@ -3834,13 +3844,13 @@ g_main_context_prepare_unlocked (GMainContext *context,
while (ready_source) while (ready_source)
{ {
ready_source->flags |= G_SOURCE_READY; g_atomic_int_or (&ready_source->flags, G_SOURCE_READY);
ready_source = ready_source->priv->parent_source; ready_source = ready_source->priv->parent_source;
} }
} }
} }
if (source->flags & G_SOURCE_READY) if (g_atomic_int_get (&source->flags) & G_SOURCE_READY)
{ {
n_ready++; n_ready++;
current_priority = source->priority; current_priority = source->priority;
@ -4106,7 +4116,7 @@ g_main_context_check_unlocked (GMainContext *context,
if ((n_ready > 0) && (source->priority > max_priority)) if ((n_ready > 0) && (source->priority > max_priority))
break; break;
if (!(source->flags & G_SOURCE_READY)) if (!(g_atomic_int_get (&source->flags) & G_SOURCE_READY))
{ {
gboolean result; gboolean result;
gboolean (* check) (GSource *source); gboolean (* check) (GSource *source);
@ -4177,13 +4187,13 @@ g_main_context_check_unlocked (GMainContext *context,
while (ready_source) while (ready_source)
{ {
ready_source->flags |= G_SOURCE_READY; g_atomic_int_or (&ready_source->flags, G_SOURCE_READY);
ready_source = ready_source->priv->parent_source; ready_source = ready_source->priv->parent_source;
} }
} }
} }
if (source->flags & G_SOURCE_READY) if (g_atomic_int_get (&source->flags) & G_SOURCE_READY)
{ {
g_source_ref (source); g_source_ref (source);
g_ptr_array_add (context->pending_dispatches, source); g_ptr_array_add (context->pending_dispatches, source);

View File

@ -275,7 +275,7 @@ struct _GSource
GMainContext *context; GMainContext *context;
gint priority; gint priority;
guint flags; guint flags; /* (atomic) */
guint source_id; guint source_id;
GSList *poll_fds; GSList *poll_fds;