[glib] GDataList: don't hold the bitlock over callbacks



commit c91720255261222d7be685f3a8f039706f04cce5
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Jun 6 23:23:29 2011 -0400

    GDataList: don't hold the bitlock over callbacks
    
    g_datalist_id_clear_i was dropping the dataset lock around
    the destroy notifies, but kept the bitlock. This was causing
    deadlocks when finalizing widgets.

 glib/gdataset.c |   45 +++++++++++++++++++++++++++++----------------
 1 files changed, 29 insertions(+), 16 deletions(-)
---
diff --git a/glib/gdataset.c b/glib/gdataset.c
index e1b55c1..0c1f9c1 100644
--- a/glib/gdataset.c
+++ b/glib/gdataset.c
@@ -176,8 +176,7 @@ struct _GDataset
 
 /* --- prototypes --- */
 static inline GDataset*	g_dataset_lookup		(gconstpointer	  dataset_location);
-static inline void	g_datalist_clear_i		(GData		**datalist, 
-							 gboolean         unlock_dataset);
+static inline void	g_datalist_clear_i		(GData		**datalist);
 static void		g_dataset_destroy_internal	(GDataset	 *dataset);
 static inline gpointer	g_data_set_internal		(GData     	**datalist,
 							 GQuark   	  key_id,
@@ -228,8 +227,8 @@ g_datalist_unlock (GData **datalist)
 /* Called with the datalist lock held, or the dataset global
  * lock for dataset lists
  */
-void
-g_datalist_clear_i (GData **datalist, gboolean unlock_dataset)
+static void
+g_datalist_clear_i (GData **datalist)
 {
   GData *data;
   gint i;
@@ -239,15 +238,13 @@ g_datalist_clear_i (GData **datalist, gboolean unlock_dataset)
 
   if (data)
     {
-      if (unlock_dataset)
-	G_UNLOCK (g_dataset_global);
+      G_UNLOCK (g_dataset_global);
       for (i = 0; i < data->len; i++)
-	{
-	  if (data->data[i].data && data->data[i].destroy)
-	    data->data[i].destroy (data->data[i].data);
-	}
-      if (unlock_dataset)
-	G_LOCK (g_dataset_global);
+        {
+          if (data->data[i].data && data->data[i].destroy)
+            data->data[i].destroy (data->data[i].data);
+        }
+      G_LOCK (g_dataset_global);
 
       g_free (data);
     }
@@ -258,19 +255,35 @@ g_datalist_clear_i (GData **datalist, gboolean unlock_dataset)
  * g_datalist_clear:
  * @datalist: a datalist.
  *
- * Frees all the data elements of the datalist. The data elements'
- * destroy functions are called if they have been set.
+ * Frees all the data elements of the datalist.
+ * The data elements' destroy functions are called
+ * if they have been set.
  **/
 void
 g_datalist_clear (GData **datalist)
 {
+  GData *data;
+  gint i;
+
   g_return_if_fail (datalist != NULL);
 
   g_datalist_lock (datalist);
 
-  g_datalist_clear_i (datalist, FALSE);
+  data = G_DATALIST_GET_POINTER (datalist);
+  G_DATALIST_SET_POINTER (datalist, NULL);
 
   g_datalist_unlock (datalist);
+
+  if (data)
+    {
+      for (i = 0; i < data->len; i++)
+        {
+          if (data->data[i].data && data->data[i].destroy)
+            data->data[i].destroy (data->data[i].data);
+        }
+
+      g_free (data);
+    }
 }
 
 /* HOLDS: g_dataset_global_lock */
@@ -307,7 +320,7 @@ g_dataset_destroy_internal (GDataset *dataset)
 	  break;
 	}
       
-      g_datalist_clear_i (&dataset->datalist, TRUE);
+      g_datalist_clear_i (&dataset->datalist);
       dataset = g_dataset_lookup (dataset_location);
     }
 }



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