--- /work/glib/glib-2.11.0orig/./gobject/gtype.c	2006-04-23 07:21:08.000000000 +0300
+++ ./gobject/gtype.c	2006-05-26 15:21:33.000000000 +0300
@@ -123,6 +123,9 @@ static GStaticRWLock            type_rw_
 
 
 /* --- typedefs --- */
+#ifdef G_THREADS_ENABLED
+typedef struct _TypeNodeLock	TypeNodeLock;
+#endif
 typedef struct _TypeNode        TypeNode;
 typedef struct _CommonData      CommonData;
 typedef struct _IFaceData       IFaceData;
@@ -178,6 +181,14 @@ typedef enum
 } InitState;
 
 /* --- structures --- */
+#ifdef G_THREADS_ENABLED
+struct _TypeNodeLock
+{
+  GCond       *condition;
+  GMutex      *mutex;
+  guint        number_waiting;
+};
+#endif
 struct _TypeNode
 {
   GTypePlugin *plugin;
@@ -191,6 +202,10 @@ struct _TypeNode
   TypeData * volatile data;
   GQuark       qname;
   GData       *global_gdata;
+#ifdef G_THREADS_ENABLED
+  TypeNodeLock *lock;
+  GThread      *locking_thread;
+#endif
   union {
     IFaceEntry  *iface_entries;		/* for !iface types */
     GType       *prerequisistes;
@@ -410,6 +425,10 @@ type_node_any_new_W (TypeNode           
   node->data = NULL;
   node->qname = g_quark_from_string (name);
   node->global_gdata = NULL;
+#ifdef G_THREADS_ENABLED
+  node->lock = NULL;
+  node->locking_thread = NULL;
+#endif
   
   g_hash_table_insert (static_type_nodes_ht,
 		       GUINT_TO_POINTER (node->qname),
@@ -498,6 +517,76 @@ type_lookup_iface_entry_L (TypeNode *nod
   return NULL;
 }
 
+static gboolean
+type_node_lock_Wm (TypeNode *node)
+{
+#ifdef G_THREADS_ENABLED
+  TypeNodeLock *lock;
+  GThread *self;
+  gboolean first_time;
+
+  if (!node || !g_thread_supported ())
+    return TRUE;
+  self = g_thread_self ();
+  if (node->locking_thread == NULL)
+    {
+      node->locking_thread = self;
+      return TRUE;
+    }
+  if (node->locking_thread == self)
+    return FALSE; /* Invalid recursion */
+  if (!node->lock)
+    {
+      node->lock = g_malloc0 (sizeof(TypeNodeLock));
+      node->lock->condition = g_cond_new ();
+      node->lock->mutex = g_mutex_new ();
+    }
+  lock = node->lock;
+  lock->number_waiting++;
+  first_time = TRUE;
+  for (;;)
+    {
+      G_WRITE_UNLOCK (&type_rw_lock);
+      if (first_time)
+	{
+	  g_mutex_lock (lock->mutex);
+	  first_time = FALSE;
+	}
+      g_cond_wait (lock->condition, lock->mutex);
+      G_WRITE_LOCK (&type_rw_lock);
+      if (node->locking_thread == NULL)
+	{
+	  node->locking_thread = self;
+	  lock->number_waiting--;
+	  g_mutex_unlock (lock->mutex);
+	  break;
+	}
+    }
+#endif
+  return TRUE;
+}
+
+static void
+type_node_unlock_W (TypeNode *node)
+{
+#ifdef G_THREADS_ENABLED
+  if (!node || !g_thread_supported ())
+    return;
+  node->locking_thread = NULL;
+  if (node->lock)
+    {
+      if (node->lock->number_waiting > 0)
+	  g_cond_signal (node->lock->condition);
+      else
+	{
+	  g_cond_free (node->lock->condition);
+	  g_free (node->lock);
+	  node->lock = NULL;
+	}
+    }
+#endif
+}
+
 static inline gboolean
 type_lookup_prerequisite_L (TypeNode *iface,
 			    GType     prerequisite_type)
@@ -1054,6 +1143,15 @@ type_data_ref_Wm (TypeNode *node)
       GTypeValueTable tmp_value_table;
       
       g_assert (node->plugin != NULL);
+      if (!type_node_lock_Wm (node))
+	INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
+      if (node->data)
+	{
+	  g_assert (node->data->common.ref_count > 0);
+	  node->data->common.ref_count += 1;
+	  type_node_unlock_W (node);
+	  return;
+	}
       
       if (pnode)
 	{
@@ -1076,6 +1174,7 @@ type_data_ref_Wm (TypeNode *node)
       type_data_make_W (node, &tmp_info,
 			check_value_table_I (NODE_NAME (node),
 					     &tmp_value_table) ? &tmp_value_table : NULL);
+      type_node_unlock_W (node);
     }
   else
     {
@@ -1968,8 +2067,12 @@ type_data_last_unref_Wm (GType    type,
   
   g_return_if_fail (node != NULL && node->plugin != NULL);
   
+  if (!type_node_lock_Wm (node))
+    INVALID_RECURSION ("GType class last unref ", NULL, NODE_NAME (node));
+
   if (!node->data || node->data->common.ref_count == 0)
     {
+      type_node_unlock_W (node);
       g_warning ("cannot drop last reference to unreferenced type `%s'",
 		 type_descriptive_name_I (type));
       return;
@@ -2001,7 +2104,10 @@ type_data_last_unref_Wm (GType    type,
     }
   
   if (node->data->common.ref_count > 1)	/* may have been re-referenced meanwhile */
-    node->data->common.ref_count -= 1;
+    {
+      node->data->common.ref_count -= 1;
+      type_node_unlock_W (node);
+    }
   else
     {
       GType ptype = NODE_PARENT_TYPE (node);
@@ -2051,6 +2157,7 @@ type_data_last_unref_Wm (GType    type,
        */
       g_free (tdata);
       
+      type_node_unlock_W (node);
       G_WRITE_UNLOCK (&type_rw_lock);
       g_type_plugin_unuse (node->plugin);
       G_WRITE_LOCK (&type_rw_lock);
@@ -2355,7 +2462,8 @@ g_type_class_ref (GType type)
   G_WRITE_LOCK (&type_rw_lock);
   node = lookup_type_node_I (type);
   if (node && node->is_classed && node->data &&
-      node->data->class.class && node->data->common.ref_count > 0)
+      node->data->class.class && node->data->common.ref_count > 0 &&
+      node->data->class.init_state == INITIALIZED)
     {
       type_data_ref_Wm (node);
       G_WRITE_UNLOCK (&type_rw_lock);
@@ -2374,21 +2482,34 @@ g_type_class_ref (GType type)
   
   type_data_ref_Wm (node);
   
+  if (node->data->class.class)
+    if (node->data->class.init_state != INITIALIZED)
+      /* Another thread may be initialising the class, so wait for it */
+      if (type_node_lock_Wm (node))
+	type_node_unlock_W (node);
+
   if (!node->data->class.class)
     {
       GType ptype = NODE_PARENT_TYPE (node);
       GTypeClass *pclass = NULL;
-      
-      if (ptype)
+    
+      if (!type_node_lock_Wm (node))
+	INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
+      if (!node->data->class.class)
 	{
-	  G_WRITE_UNLOCK (&type_rw_lock);
-	  pclass = g_type_class_ref (ptype);
-	  if (node->data->class.class)
-            INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
-	  G_WRITE_LOCK (&type_rw_lock);
-	}
       
-      type_class_init_Wm (node, pclass);
+	  if (ptype)
+	    {
+	      G_WRITE_UNLOCK (&type_rw_lock);
+	      pclass = g_type_class_ref (ptype);
+	      if (node->data->class.class)
+		INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
+	      G_WRITE_LOCK (&type_rw_lock);
+	    }
+      
+	  type_class_init_Wm (node, pclass);
+	}
+      type_node_unlock_W (node);
     }
   G_WRITE_UNLOCK (&type_rw_lock);
   
