[glib/gobject-speedups: 12/13] Avoid allocating GObjectNotifyQueue




commit 0732f8ff6a02c9b6bf64274a5cad76692e962bb6
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun May 15 22:12:10 2022 -0400

    Avoid allocating GObjectNotifyQueue

 gobject/gobject.c           | 31 ++++++++++++++-----------
 gobject/gobject.h           | 19 ++++++++++++++-
 tests/gobject/performance.c | 56 ++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 89 insertions(+), 17 deletions(-)
---
diff --git a/gobject/gobject.c b/gobject/gobject.c
index d272f85875..1f43b28422 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -239,16 +239,6 @@ static void object_interface_check_properties           (gpointer        check_d
                                                         gpointer        g_iface);
 static void                weak_locations_free_unlocked (GSList **weak_locations);
 
-/* --- typedefs --- */
-typedef struct _GObjectNotifyQueue            GObjectNotifyQueue;
-
-struct _GObjectNotifyQueue
-{
-  GSList  *pspecs;
-  guint16  n_pspecs;
-  guint16  freeze_count;
-};
-
 /* --- variables --- */
 G_LOCK_DEFINE_STATIC (closure_array_mutex);
 G_LOCK_DEFINE_STATIC (weak_refs_mutex);
@@ -280,6 +270,13 @@ g_object_notify_queue_free (gpointer data)
 static GObjectNotifyQueue*
 g_object_notify_queue_freeze (GObject  *object,
                               gboolean  conditional)
+{
+  return G_OBJECT_GET_CLASS (object)->freeze_notify (object, conditional);
+}
+
+static GObjectNotifyQueue*
+g_object_default_freeze_notify (GObject  *object,
+                                gboolean  conditional)
 {
   GObjectNotifyQueue *nqueue;
 
@@ -314,6 +311,13 @@ g_object_notify_queue_freeze (GObject  *object,
 static void
 g_object_notify_queue_thaw (GObject            *object,
                             GObjectNotifyQueue *nqueue)
+{
+  G_OBJECT_GET_CLASS (object)->thaw_notify (object, nqueue);
+}
+
+static void
+g_object_default_thaw_notify (GObject            *object,
+                              GObjectNotifyQueue *nqueue)
 {
   GParamSpec *pspecs_mem[16], **pspecs, **free_me = NULL;
   GSList *slist;
@@ -528,6 +532,8 @@ g_object_do_class_init (GObjectClass *class)
   class->finalize = g_object_finalize;
   class->dispatch_properties_changed = g_object_dispatch_properties_changed;
   class->notify = NULL;
+  class->freeze_notify = g_object_default_freeze_notify;
+  class->thaw_notify = g_object_default_thaw_notify;
 
   /**
    * GObject::notify:
@@ -2074,9 +2080,8 @@ g_object_new_internal (GObjectClass          *class,
 
       if (CLASS_HAS_NOTIFY (class))
         {
-          /* This will have been setup in g_object_init() */
-          nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue);
-          g_assert (nqueue != NULL);
+          nqueue = g_object_notify_queue_freeze (object, FALSE);
+          g_object_notify_queue_thaw (object, nqueue);
         }
 
       /* We will set exactly n_construct_properties construct
diff --git a/gobject/gobject.h b/gobject/gobject.h
index c67794ae50..60c55cd1d2 100644
--- a/gobject/gobject.h
+++ b/gobject/gobject.h
@@ -246,6 +246,16 @@ typedef void (*GObjectFinalizeFunc)     (GObject      *object);
  */
 typedef void (*GWeakNotify)            (gpointer      data,
                                         GObject      *where_the_object_was);
+
+typedef struct _GObjectNotifyQueue            GObjectNotifyQueue;
+
+struct _GObjectNotifyQueue
+{
+  GSList  *pspecs;
+  guint16  n_pspecs;
+  guint16  freeze_count;
+};
+
 /**
  * GObject:
  *
@@ -366,12 +376,19 @@ struct  _GObjectClass
   /* called when done constructing */
   void      (*constructed)             (GObject        *object);
 
+  GObjectNotifyQueue *
+             (*freeze_notify)           (GObject        *object,
+                                         gboolean        conditional);
+
+  void       (*thaw_notify)             (GObject        *object,
+                                         GObjectNotifyQueue *nqueue);
+
   /*< private >*/
   gsize                flags;
 
   gsize         n_construct_properties;
   /* padding */
-  gpointer     pdummy[5];
+  gpointer     pdummy[3];
 };
 
 /**
diff --git a/tests/gobject/performance.c b/tests/gobject/performance.c
index f77c93b5d0..c80720a5d6 100644
--- a/tests/gobject/performance.c
+++ b/tests/gobject/performance.c
@@ -253,6 +253,7 @@ typedef struct _ComplexObjectClass ComplexObjectClass;
 struct _ComplexObject
 {
   GObject parent_instance;
+  GObjectNotifyQueue nqueue;
   int val1;
   char *val2;
 };
@@ -298,7 +299,7 @@ static guint complex_signals[COMPLEX_LAST_SIGNAL] = { 0 };
 static void
 complex_object_finalize (GObject *object)
 {
-  ComplexObject *c = COMPLEX_OBJECT (object);
+  ComplexObject *c = (ComplexObject *) object;
 
   g_free (c->val2);
 
@@ -311,7 +312,7 @@ complex_object_set_property (GObject         *object,
                             const GValue    *value,
                             GParamSpec      *pspec)
 {
-  ComplexObject *complex = COMPLEX_OBJECT (object);
+  ComplexObject *complex = (ComplexObject *)object;
 
   switch (prop_id)
     {
@@ -334,7 +335,7 @@ complex_object_get_property (GObject         *object,
                             GValue          *value,
                             GParamSpec      *pspec)
 {
-  ComplexObject *complex = COMPLEX_OBJECT (object);
+  ComplexObject *complex = (ComplexObject *)object;
 
   switch (prop_id)
     {
@@ -355,6 +356,53 @@ complex_object_real_signal (ComplexObject *obj)
 {
 }
 
+static GObjectNotifyQueue *
+complex_object_freeze_notify (GObject *object,
+                              gboolean conditional)
+{
+  ComplexObject *complex = (ComplexObject *)object;
+
+  if (conditional && complex->nqueue.freeze_count == 0)
+    return NULL;
+
+  complex->nqueue.freeze_count++;
+
+  return &complex->nqueue;
+}
+
+static void
+complex_object_thaw_notify (GObject            *object,
+                            GObjectNotifyQueue *nqueue)
+{
+  int n_pspecs;
+  GParamSpec **pspecs;
+
+  /* Just make sure we never get into some nasty race condition */
+  if (G_UNLIKELY (nqueue->freeze_count == 0))
+    {
+      g_warning ("%s: property-changed notification for %s(%p) is not frozen",
+                 G_STRFUNC, G_OBJECT_TYPE_NAME (object), object);
+      return;
+    }
+
+  nqueue->freeze_count--;
+  if (nqueue->freeze_count)
+    return;
+
+  n_pspecs = 0;
+  pspecs = g_newa (GParamSpec *, nqueue->n_pspecs);
+
+  for (GSList *l = nqueue->pspecs; l; l = l->next)
+    pspecs[n_pspecs++] = l->data;
+
+  g_slist_free (nqueue->pspecs);
+  nqueue->pspecs = NULL;
+  nqueue->n_pspecs = 0;
+
+  if (n_pspecs)
+    G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, n_pspecs, pspecs);
+}
+
 static void
 complex_object_class_init (ComplexObjectClass *class)
 {
@@ -363,6 +411,8 @@ complex_object_class_init (ComplexObjectClass *class)
   object_class->finalize = complex_object_finalize;
   object_class->set_property = complex_object_set_property;
   object_class->get_property = complex_object_get_property;
+  object_class->freeze_notify = complex_object_freeze_notify;
+  object_class->thaw_notify = complex_object_thaw_notify;
 
   class->signal = complex_object_real_signal;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]