[glib: 2/4] gobject: Cleanup weak locations when the last one has been removed




commit e861f60dcbfc93b46623df8fccc9ce12c7f9d1e1
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Wed Sep 15 22:13:28 2021 +0200

    gobject: Cleanup weak locations when the last one has been removed
    
    As per the previous change, an object that had weak locations set may
    need to lock again the weak locations mutex during qdata cleanup, but
    we can avoid this when we know we're removing the last location, by
    removing the qdata entry and freeing the data.
    
    In case a new location is needed for the same object, new data will be
    added.
    
    However, by doing this the weak locations during dispose may be
    invalidated once the weak locations lock is passed, so check again if
    this is the case while removing them.

 gobject/gobject.c         | 13 ++++++++++---
 gobject/tests/reference.c | 12 ++++++++++++
 2 files changed, 22 insertions(+), 3 deletions(-)
---
diff --git a/gobject/gobject.c b/gobject/gobject.c
index c558c1197..4f4a463ef 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -3536,10 +3536,11 @@ g_object_unref (gpointer _object)
             }
 
           /* We got the lock first, so the object will definitely die
-           * now. Clear out all the weak references.
+           * now. Clear out all the weak references, if they're still set.
            */
-          weak_locations_free_unlocked (weak_locations);
-          g_datalist_id_remove_no_notify (&object->qdata, quark_weak_locations);
+          weak_locations = g_datalist_id_remove_no_notify (&object->qdata,
+                                                           quark_weak_locations);
+          g_clear_pointer (&weak_locations, weak_locations_free_unlocked);
 
           g_rw_lock_writer_unlock (&weak_locations_lock);
         }
@@ -4731,6 +4732,12 @@ g_weak_ref_set (GWeakRef *weak_ref,
           g_assert (weak_locations != NULL);
 
           *weak_locations = g_slist_remove (*weak_locations, weak_ref);
+
+          if (!*weak_locations)
+            {
+              weak_locations_free_unlocked (weak_locations);
+              g_datalist_id_remove_no_notify (&old_object->qdata, quark_weak_locations);
+            }
         }
 
       /* Add the weak ref to the new object */
diff --git a/gobject/tests/reference.c b/gobject/tests/reference.c
index de49ff1fd..e84c66467 100644
--- a/gobject/tests/reference.c
+++ b/gobject/tests/reference.c
@@ -558,6 +558,18 @@ test_weak_ref (void)
 
   g_weak_ref_clear (&weak3);
 
+  /* unset dynamic_weak... */
+  g_weak_ref_set (dynamic_weak, NULL);
+  g_assert_null (g_weak_ref_get (dynamic_weak));
+
+  /* initializing a weak reference to an object that had before works */
+  g_weak_ref_set (dynamic_weak, obj2);
+  tmp = g_weak_ref_get (dynamic_weak);
+  g_assert_true (tmp == obj2);
+  g_assert_cmpint (obj2->ref_count, ==, 2);
+  g_object_unref (tmp);
+  g_assert_cmpint (obj2->ref_count, ==, 1);
+
   /* clear and free dynamic_weak... */
   g_weak_ref_clear (dynamic_weak);
 


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