kernel poll bug workaround prototype ...



Hi guys,

	I don't have time to continue this - and while it appears to work
for me; I don't have a nice warm feeling about this code - especialy the
Irix workaround - which is a mystery to me.

	Essentialy this is to workaround breakage in all 2.4 kernels up to
2.4.9pre4 in linux/fs/select.c (sys_poll):

	/* Do a sanity check on nfds ... */
	if (nfds > current->files->max_fds)
		return -EINVAL;

	This being in fact an insanity check, since it is possible to have
multiple polls per file descriptor.

	The patch works around this by discarding the priority mechansim,
and sorting the polls by fd order - then at 'poll' time we coalesce events
that we are interested in into the same record, and then later at check
time we de-mux them out into their polls again to be dispatched
separately.

	In a word - it sucks; since I have no need for this now ( having
re-written the linc oddness that poked this ) I have two proposed
solutions; first this patch:

       if ((*poll_func) (fds, n_fds, timeout) < 0 && errno != EINTR)
-	g_warning ("poll(2) failed due to: %s.",
-		   g_strerror (errno));
+        {
+          if (errno == EINVAL)
+	    g_warning ("poll(2) failed due to an invalid argument. If all
the "
+		       "file descriptors are valid - it is most likely "
+		       "that you've hit a linux-2.4 kernel bug whereas "
+		       "n_fds must be < max file descriptor.");
+	  else
+	    g_warning ("poll(2) failed due to: %s.",
+		       g_strerror (errno));
+        }

	Which might be helpful to stop people re-tracing the same steps.

	And then the full 'fix':

Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/glib/ChangeLog,v
retrieving revision 1.794
diff -u -r1.794 ChangeLog
--- ChangeLog	2001/08/15 09:11:23	1.794
+++ ChangeLog	2001/08/17 16:47:37
@@ -1,3 +1,10 @@
+2001-08-16  Michael Meeks  <michael ximian com>
+
+	* glib/gmain.c (g_main_context_add_poll_unlocked): sort by
+	file descriptor not priority.
+	(g_main_context_query): coalesce polls on the same fd.
+	(g_main_context_check): coalesce collect.
+
 Wed Aug 15 11:09:56 2001  Tim Janik  <timj gtk org>

 	* Makefile.am: let the generated .pc files depend on config.status,
Index: glib/gmain.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gmain.c,v
retrieving revision 1.64
diff -u -r1.64 gmain.c
--- glib/gmain.c	2001/07/17 08:49:23	1.64
+++ glib/gmain.c	2001/08/17 16:47:37
@@ -1953,7 +1953,7 @@
 		      GPollFD      *fds,
 		      gint          n_fds)
 {
-  gint n_poll;
+  gint n_poll, last_fd = -1;
   GPollRec *pollrec;

   LOCK_CONTEXT (context);
@@ -1964,20 +1964,29 @@
     {
       if (pollrec->fd->events)
 	{
-	  if (n_poll < n_fds)
+	  if (last_fd == pollrec->fd->fd) /* Coalesce */
 	    {
-	      fds[n_poll].fd = pollrec->fd->fd;
-	      /* In direct contradiction to the Unix98 spec, IRIX runs into
-	       * difficulty if you pass in POLLERR, POLLHUP or POLLNVAL
-	       * flags in the events field of the pollfd while it should
-	       * just ignoring them. So we mask them out here.
-	       */
-	      fds[n_poll].events = pollrec->fd->events & ~(G_IO_ERR|G_IO_HUP|G_IO_NVAL);
-	      fds[n_poll].revents = 0;
+	      if (n_poll < n_fds)
+                fds[n_poll].events = fds [n_poll].events |
+                                     (pollrec->fd->events & ~(G_IO_ERR|G_IO_HUP|G_IO_NVAL));
 	    }
-	  n_poll++;
+	  else
+	    {
+	      if (n_poll < n_fds)
+	        {
+	          fds[n_poll].fd = pollrec->fd->fd;
+		  /* In direct contradiction to the Unix98 spec, IRIX runs into
+		   * difficulty if you pass in POLLERR, POLLHUP or POLLNVAL
+		   * flags in the events field of the pollfd while it should
+		   * just ignoring them. So we mask them out here.
+		   */
+		  fds[n_poll].events = pollrec->fd->events & ~(G_IO_ERR|G_IO_HUP|G_IO_NVAL);
+		  fds[n_poll].revents = 0;
+		}
+	      n_poll++;
+	    }
 	}
-
+      last_fd = pollrec->fd->fd;
       pollrec = pollrec->next;
     }

@@ -2018,7 +2027,7 @@
   GSource *source;
   GPollRec *pollrec;
   gint n_ready = 0;
-  gint i;
+  gint i, last_fd;

   LOCK_CONTEXT (context);

@@ -2053,13 +2062,16 @@

   pollrec = context->poll_records;
   i = 0;
+  last_fd = -1;
   while (i < n_fds)
     {
       if (pollrec->fd->events)
 	{
-	  pollrec->fd->revents = fds[i].revents;
-	  i++;
+          pollrec->fd->revents = fds[i].revents & pollrec->fd->events;
+	  if (last_fd != pollrec->fd->fd)
+	    i++;
 	}
+      last_fd = pollrec->fd->fd;
       pollrec = pollrec->next;
     }

@@ -2508,7 +2520,7 @@
   if (n_fds || timeout != 0)
     {
 #ifdef	G_MAIN_POLL_DEBUG
-      g_print ("g_main_poll(%d) timeout: %d\n", n_fds, timeout);
+      g_print ("g_main_poll(%p, %d) timeout: %d\n", context, n_fds, timeout);
       poll_timer = g_timer_new ();
 #endif

@@ -2521,7 +2533,7 @@
 	g_warning ("poll(2) failed due to: %s.",
 		   g_strerror (errno));

-#ifdef	G_MAIN_POLL_DEBUG
+#ifdef G_MAIN_POLL_DEBUG
       LOCK_CONTEXT (context);

       g_print ("g_main_poll(%d) timeout: %d - elapsed %12.10f seconds",
@@ -2618,7 +2630,7 @@

   lastrec = NULL;
   pollrec = context->poll_records;
-  while (pollrec && priority >= pollrec->priority)
+  while (pollrec && fd->fd > pollrec->fd->fd)
     {
       lastrec = pollrec;
       pollrec = pollrec->next;

	HTH,

		Michael.

-- 
 mmeeks gnu org  <><, Pseudo Engineer, itinerant idiot





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