Make type_data_unref_U not take locks in the common case
authorEdward Hervey <bilboed@bilboed.com>
Thu, 24 Sep 2009 09:45:13 +0000 (11:45 +0200)
committerAlexander Larsson <alexl@redhat.com>
Mon, 30 Nov 2009 19:52:32 +0000 (20:52 +0100)
https://bugzilla.gnome.org/show_bug.cgi?id=585375

gobject/gtype.c

index 2a4925c..af36382 100644 (file)
@@ -2346,11 +2346,12 @@ static inline void
 type_data_unref_U (TypeNode *node,
                    gboolean  uncached)
 {
-  G_WRITE_LOCK (&type_rw_lock);
-  g_assert (node->data && NODE_REFCOUNT (node) > 0);
-  if (NODE_REFCOUNT (node) > 1)
-    g_atomic_int_add ((int *) &node->ref_count, -1);
-  else
+  guint current;
+
+  do {
+    current = NODE_REFCOUNT (node);
+
+    if (current <= 1)
     {
       if (!node->plugin)
        {
@@ -2358,13 +2359,17 @@ type_data_unref_U (TypeNode *node,
                     NODE_NAME (node));
          return;
        }
-      G_WRITE_UNLOCK (&type_rw_lock);
+
+      g_assert (current > 0);
+
       g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
       G_WRITE_LOCK (&type_rw_lock);
       type_data_last_unref_Wm (node, uncached);
+      G_WRITE_UNLOCK (&type_rw_lock);
       g_static_rec_mutex_unlock (&class_init_rec_mutex);
+      return;
     }
-  G_WRITE_UNLOCK (&type_rw_lock);
+  } while (!g_atomic_int_compare_and_exchange ((int *) &node->ref_count, current, current - 1));
 }
 
 /**