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)
{
gboolean callback_called = FALSE; /* (atomic) */
gboolean callback_called; /* (atomic) */
gboolean called;
g_atomic_int_set (&callback_called, FALSE);
gulong id = g_cancellable_connect (cancellable,
G_CALLBACK (on_racy_cancellable_cancelled),
&callback_called, NULL);
@ -780,13 +783,14 @@ test_cancellable_cancel_reset_connect_races (void)
GThread *resetting_thread = NULL;
GThread *cancelling_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 "
" and resetting a GCancellable");
cancellable = g_cancellable_new ();
g_atomic_int_set (&callback_called, FALSE);
g_cancellable_connect (cancellable, G_CALLBACK (on_racy_cancellable_cancelled),
&callback_called, NULL);
g_assert_false (g_atomic_int_get (&callback_called));

View File

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

View File

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