From 56dc2a390be0210c36368288c888bdacff80f705 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 19 Jan 2024 11:38:40 +0100 Subject: [PATCH] gobject: rework g_object_notify_queue_freeze() to use g_datalist_id_update_atomic() A common pattern is to look whether a GData entry exists, and if it doesn't, add it. For that, we currently always must take a OPTIONAL_BIT_LOCK_NOTIFY lock. This can be avoided, because GData already uses an internal mutex. By using g_datalist_id_update_atomic(), we can perform all relevant operations while holding that mutex. Move functionality from g_object_notify_queue_freeze() inside g_datalist_id_update_atomic(). The goal will be to drop the OPTIONAL_BIT_LOCK_NOTIFY lock in a later commit. --- gobject/gobject.c | 62 +++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/gobject/gobject.c b/gobject/gobject.c index 70e7e00b4..6be68551e 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -667,18 +667,45 @@ g_object_notify_queue_free (gpointer data) } static GObjectNotifyQueue * -g_object_notify_queue_create_queue_frozen (GObject *object) +g_object_notify_queue_new_frozen (void) { GObjectNotifyQueue *nqueue; - nqueue = g_new0 (GObjectNotifyQueue, 1); - + nqueue = g_new (GObjectNotifyQueue, 1); *nqueue = (GObjectNotifyQueue){ .freeze_count = 1, }; - g_datalist_id_set_data_full (&object->qdata, quark_notify_queue, - nqueue, g_object_notify_queue_free); + return nqueue; +} + +static gpointer +g_object_notify_queue_freeze_cb (gpointer *data, + GDestroyNotify *destroy_notify, + gpointer user_data) +{ + GObject *object = user_data; + GObjectNotifyQueue *nqueue = *data; + + if (!nqueue) + { + /* The nqueue doesn't exist yet. We create it, and freeze thus 1 time. */ + nqueue = g_object_notify_queue_new_frozen (); + *data = nqueue; + *destroy_notify = g_object_notify_queue_free; + } + else + { + if (nqueue->freeze_count >= 65535) + { + g_critical ("Free queue for %s (%p) is larger than 65535," + " called g_object_freeze_notify() too often." + " Forgot to call g_object_thaw_notify() or infinite loop", + G_OBJECT_TYPE_NAME (object), object); + } + else + nqueue->freeze_count++; + } return nqueue; } @@ -689,24 +716,11 @@ g_object_notify_queue_freeze (GObject *object) GObjectNotifyQueue *nqueue; object_bit_lock (object, OPTIONAL_BIT_LOCK_NOTIFY); - nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue); - if (!nqueue) - { - nqueue = g_object_notify_queue_create_queue_frozen (object); - goto out; - } - - if (nqueue->freeze_count >= 65535) - g_critical("Free queue for %s (%p) is larger than 65535," - " called g_object_freeze_notify() too often." - " Forgot to call g_object_thaw_notify() or infinite loop", - G_OBJECT_TYPE_NAME (object), object); - else - nqueue->freeze_count++; - -out: + nqueue = _g_datalist_id_update_atomic (&object->qdata, + quark_notify_queue, + g_object_notify_queue_freeze_cb, + object); object_bit_unlock (object, OPTIONAL_BIT_LOCK_NOTIFY); - return nqueue; } @@ -797,7 +811,9 @@ g_object_notify_queue_add (GObject *object, * Note that this freeze will be balanced at the end of object * initialization. */ - nqueue = g_object_notify_queue_create_queue_frozen (object); + nqueue = g_object_notify_queue_new_frozen (); + g_datalist_id_set_data_full (&object->qdata, quark_notify_queue, + nqueue, g_object_notify_queue_free); } }