[comp.windows.x] Xlib not seeing net connection drop?

mouse@LARRY.MCRCIM.MCGILL.EDU (der Mouse) (06/25/89)

I'm seeing a strange problem which appears to be something strange in
the guts of Xlib, or (perhaps) my failure to notice something buried
somewhere in the Xlib documentation.

Preparatory facts:

- I wrote my own terminal emulator ("mterm") using bare Xlib.
- MIT X11R3 on Sun-3s running release 3.5; bwtwo and cgfour displays.
- X is always started via the xinit mechanism.

When killing xinit's distinguished client (it's one I wrote expressly
for the purpose of being xinit's distinguished client), I will
sometimes later see mterms (always on other machines) running in the
background soaking up as much cpu as UNIX is willing to give them,
clearly in infinite loops, left over from the X session.

Taking core dumps (with "kill -STOP" and "gcore") revealed that the
infinite loop is in the code that reads from the pty and the X
connection.  This code looks roughly like this:

	while (1)
	 { if (XQLength(disp) > 0)
	    { read events and act on them
	    }
	   choose a timeout for the select - see below
	   call select() on the pty and XConnectionNumber(disp)
	   if (the select timed out)
	    { if (the window needs updating) update it
	      if (there might be stuff to flush to the X server)
	       { XSync(disp,False); /* see below */
	       }
	      continue;
	    }
	   if (select indicates something on the X connection)
	    { XEventsQueued(disp,QueuedAfterReading);
	      continue;
	    }
	   if (select indicates something on the pty)
	    { handle stuff on the pty
	    }
	 }

The timeout on the select is chosen based on whether we think the X
connection might need flushing and whether the window needs updating.
If either one is true, the timeout is zero; otherwise, the timeout is
non-zero (depending on other factors), from about half a second to
infinity.  (The XSync call used to be XFlush, but if I do that there's
a race condition involving scrolling that manifests as damaged
characters not getting repaired when the window is scrolling rapidly
and is partially obscured.)

The problem seems to be that I'm stuck in an infinite loop, with
select() perpetually indicating the presence of something on the X
connection.  (For some reason, Xlib never either reads it or notices
EOF.)

What I've resorted to for now is rather inelegant - I count the number
of times I call XEventsQueued, clearing this count each time I actually
read an event (in the if at the top of the loop), and if the count goes
over 10000, I summarily exit().  (It remains to be seen whether this is
a complete solution, but I certainly can't see how it would fail.)  All
other ways I've come up with involves calling Xlib internal routines
directly, which is even more inelegant. :-P

(I know, If I were using Xt, the solution would be to give the pty fd
to the toolkit as another source of input.  But I'm not using Xt.)

What's the proper Xlib solution?

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

eric@pyramid.pyramid.com (Eric Bergan) (06/26/89)

In article <8906251323.AA27600@Larry.McRCIM.McGill.EDU> mouse@LARRY.MCRCIM.MCGILL.EDU (der Mouse) writes:
>I'm seeing a strange problem which appears to be something strange in
>the guts of Xlib, or (perhaps) my failure to notice something buried
>somewhere in the Xlib documentation.
>
>When killing xinit's distinguished client (it's one I wrote expressly
>for the purpose of being xinit's distinguished client), I will
>sometimes later see mterms (always on other machines) running in the
>background soaking up as much cpu as UNIX is willing to give them,
>clearly in infinite loops, left over from the X session.
>
>Taking core dumps (with "kill -STOP" and "gcore") revealed that the
>infinite loop is in the code that reads from the pty and the X
>connection.  This code looks roughly like this:
>
>	while (1)
>	 { if (XQLength(disp) > 0)
>	    { read events and act on them
>	    }
>	   choose a timeout for the select - see below
>	   call select() on the pty and XConnectionNumber(disp)
>	   if (the select timed out)
>	    { if (the window needs updating) update it
>	      if (there might be stuff to flush to the X server)
>	       { XSync(disp,False); /* see below */
>	       }
>	      continue;
>	    }
>	   if (select indicates something on the X connection)
>	    { XEventsQueued(disp,QueuedAfterReading);
>	      continue;
>	    }
>	   if (select indicates something on the pty)
>	    { handle stuff on the pty
>	    }
>	 }

	xperfmon seems to suffer from the same problem. The select down
in the Xlib is not reacting properly to the EOF and instead, just ends
up looping, doing lots of select()'s. The problem may be with any application
that tries to do select()s on the same fd's that the Xlib is using. 

	Has anyone come up with a workaround (or fix) for either Xlib
or xperfmon?



					eric
					...!pyramid!eric
-- 

					eric
					...!pyramid!eric

janssen@holmes (Bill Janssen) (06/26/89)

You might try looking for bytes on the wire, thusly:

	while (1)
	 { if (XQLength(disp) > 0)
	    { read events and act on them
	    }
	   choose a timeout for the select - see below
	   call select() on the pty and XConnectionNumber(disp)
	   if (the select timed out)
	    { if (the window needs updating) update it
	      if (there might be stuff to flush to the X server)
	       { XSync(disp,False); /* see below */
	       }
	      continue;
	    }
	   if (select indicates something on the X connection)
	    {
+	      unsigned long count;
+
+	      if (ioctl(ConnectionNumber(disp), FIONREAD, &count) == 0
+		  && count < 1)
+		EOFonXconnectionRoutine();
+	      else
		XEventsQueued(disp,QueuedAfterReading);
	      continue;
	    }
	   if (select indicates something on the pty)
	    { handle stuff on the pty
	    }
	 }

Should work on SunOS 3.5.  Properly speaking, the routine to be called
should handle exceptions on that fd, not just EOF.  Include sys/filio.h
to get the definition of FIONREAD.

Bill
Bill Janssen        janssen@xerox.com      (415) 494-4763
Xerox Palo Alto Research Center
333 Coyote Hill Road, Palo Alto, California   94304