gnome-session taking 99% CPU time - I think I have it!



I think I'm on to this bug. It occurs for me after I shut down an
application. It turns out that gnome-session is still polling a
file descriptor corresponding to an ICE connection which has
gone away.

I am working with a CVS checkout from the HEAD branch from
981217. I run enlightenment as my WM under gnome-session.

This is because of kludgy code that was never fixed in
gnome-libs/libgnomeui/gnome-ice.c, function new_ice_connection,
when opening==false. I quote:
  /* It turns out to be easier for us to always call gdk_input_add,
     even if we are trying to remove the input.  The reason is that
     this is simpler than keeping a hash table mapping connections
     onto gdk tags.  This is losing.  */
 It certainly is: calling gdk_input_add a second time puts another
file descriptor on the polling list (and other unwanted stuff), so the
same file descriptor is on the list twice. Only one copy is removed
by gdk_input_remove, so it goes on being polled,
IceProcessMessages is called repeatedly returning
IceProcessMessagesIOError every time.

I have a preliminary patch which records the association between
gdk tags and ICE connections in a list (and prints a lot of debugging
info).
Unfortunately, although it fixes this problem when opening and closing
applications from the panel, it now causes the WM to lock completely when
closing an rxvt started from the enlightenment button. I'll have another
look at it later....


--
Peter Wainwright
Home: prw@wainpr.demon.co.uk   Work: peter.wainwright@nrpb.org.uk
http://www.wainpr.demon.co.uk
Visit the Opera Exchange Homepage at http://www.treda.co.uk/opex/
diff -U4 -r gnome-libs-old/libgnomeui/gnome-ice.c gnome-libs/libgnomeui/gnome-ice.c
--- gnome-libs-old/libgnomeui/gnome-ice.c	Thu Nov 19 15:00:46 1998
+++ gnome-libs/libgnomeui/gnome-ice.c	Mon Dec 21 21:53:59 1998
@@ -23,28 +23,70 @@
   IceProcessMessagesStatus status;
   IceConn connection = (IceConn) client_data;
 
   status = IceProcessMessages (connection, NULL, NULL);
+  if (status == IceProcessMessagesIOError) {
+    static IceConn *errors = NULL;
+    static int nerrors = 0;
+    int i;
+    for (i = 0; i < nerrors && errors[i] != connection; i++) ;
+    if (i >= nerrors) {
+       errors = g_realloc(errors, (nerrors+1)*sizeof(IceConn));
+       errors[nerrors++] = connection;
+       g_message("IO error on ICE connection %lx (%d)\n",
+  	         connection, IceConnectionNumber(connection));
+    }
+  }
   /* FIXME: handle case when status==closed.  */
 }
 
+struct _IceGdkAssoc {
+  gint tag;
+  IceConn connection;
+  struct _IceGdkAssoc *next;
+};
+
 /* This is called when a new ICE connection is made.  It arranges for
    the ICE connection to be handled via the event loop.  */
 static void
 new_ice_connection (IceConn connection, IcePointer client_data, Bool opening,
 		    IcePointer *watch_data)
 {
   gint tag;
+  static struct _IceGdkAssoc *assoc_list = NULL;
+  struct _IceGdkAssoc **passoc, *assoc;
 
   /* It turns out to be easier for us to always call gdk_input_add,
      even if we are trying to remove the input.  The reason is that
      this is simpler than keeping a hash table mapping connections
      onto gdk tags.  This is losing.  */
-  tag = gdk_input_add (IceConnectionNumber (connection),
-		       GDK_INPUT_READ, process_ice_messages,
-		       (gpointer) connection);
-  if (! opening)
-    gdk_input_remove (tag);
+  if (opening) {
+    tag = gdk_input_add (IceConnectionNumber (connection),
+			 GDK_INPUT_READ, process_ice_messages,
+			 (gpointer) connection);
+    g_message("Created new ICE connection %lx (%d) -> tag %d\n",
+	      connection, IceConnectionNumber(connection), tag);
+    assoc = g_new(struct _IceGdkAssoc, 1);
+    assoc->tag = tag;
+    assoc->connection = connection;
+    assoc->next = assoc_list;
+    assoc_list = assoc;
+  }
+  else {
+    for (passoc = &assoc_list;
+	 *passoc && (*passoc)->connection != connection;
+	 passoc = &(*passoc)->next) ;
+    if (*passoc) {
+      assoc = *passoc;
+      tag = assoc->tag;
+      g_message("Destroyed old ICE connection %lx (%d) -> tag %d\n",
+		connection, IceConnectionNumber(connection), tag);
+      gdk_input_remove (tag);
+      *passoc = assoc->next;
+      g_free(assoc);
+    }
+    else g_warning("Can't find ICE connection %lx\n", connection);
+  }
 }
 
 #endif /* HAVE_LIBSM */
 


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