[comp.windows.x] XlibInt.c bug revisited

dale@amiga.UUCP (Dale Luck) (08/18/88)

Did anyone else try fixing the _XReadEvents bug that I found in
the same way I tried? By moving the NULL test to the top of
the loop instead of at the bottom?
This is the original bug report, I have a some more observations
later after the bug report:

-------------------------------------------------------------------

VERSION:
	X11 release 2

CLIENT MACHINE:
	amiga 2000

CLIENT OPERATING SYSTEM:
	amigados V1.3

DISPLAY:
	amiga 640x400 monochrome

SYNOPSIS:
	_XReadEvents can block unnecesarrily

DESCRIPTION:
	_XReadEvents first calls _XFlush.
	If _XFlush blocks on call to write it will call _XWaitForWritable.
	This routine reads packets until it can finally write something
	out.  When  _XWaitForWritable finally can write on the socket it
	returns and _XFlush returns to _XReadEvents.  _XReadEvents then
	drops into a loop looking for something to read. If there are
	no more packets to be read it will block waiting for another packet,
	yet _XWaitForWritable may have read them all and already
	Queued them up for processing.

REPEAT-BY:
	Run xcalc and let it start up by itself. Notice it does not complete
	the calculator text on the buttons until the X-cursor enters the
	calculator region when the server sends another event the the calculator
	process.

FIX:
	The fix is to just move the while (dpy->head) to the top of the loop
	instead of the bottom in _XReadEvents.
	The following is a diff file for XlibInt.c


129c129
< 	while (dpy->head == NULL) {			***** new code *****
---
> 	do {						***** old code *****
154c154
< 	}						***** new code *****
---
> 	} while (dpy->head == NULL);			***** old code *****

Dale Luck
amiga!dale

--------------------------------------------------------------------
After applying the fix, I no longer get the falsly blocked input,
however the client can now easily go into an endless loop somewhere.
I don't have the time to look at it thoroughly right now, however I
suggest that you back out the proposed fix that I made in the bug
report and when a proper fix is invented than we install that.

The particular example I had of a client going into an infinate loop
was xterm. If I cat'ed /etc/termcap and then quickly moved the cursor
in and out of the window or bashed on the keyboard with a few quick
keys, it would freeze and the perfmon on the sun3 (my remote host running
xterm) would peg user cpu at 100%. Very suspicious. Net traffic had
also stopped as writes from the amiga were still getting to the sun3
but not making it into xterm, and there was absolutly no packets being
sent from xterm to the amiga. Thanks netstat.

Dale Luck
amiga!dale

RWS@ZERMATT.LCS.MIT.EDU (Robert Scheifler) (08/18/88)

    Date: 18 Aug 88 09:08:56 GMT
    From: oliveb!amiga!dale@AMES.ARC.NASA.GOV  (Dale Luck)

    Did anyone else try fixing the _XReadEvents bug that I found in
    the same way I tried?

No, we fixed it differently.  (The diff below has a few unrelated things
included.)  I know, I know, we did this a long time ago, and shame on us
for not having published it.

*** /tmp/,RCSt1a12252	Thu Aug 18 08:10:29 1988
--- lib/X/XlibInt.c	Thu Aug 18 08:10:36 1988
***************
*** 2,8 ****
  /* Copyright    Massachusetts Institute of Technology    1985, 1986, 1987 */
  
  #ifndef lint
! static char rcsid[] = "$Header: XlibInt.c,v 11.63 88/02/20 20:21:11 rws Exp $";
  #endif
  
  /*
--- 2,8 ----
  /* Copyright    Massachusetts Institute of Technology    1985, 1986, 1987 */
  
  #ifndef lint
! static char rcsid[] = "$Header: XlibInt.c,v 11.66 88/05/24 14:34:09 swick Exp $";
  #endif
  
  /*
***************
*** 99,105 ****
  	if (BytesReadable(dpy->fd, (char *) &pend) < 0)
  	    (*_XIOErrorFunction)(dpy);
  	if ((len = pend) < sizeof(xReply))
! 	    return(0);
  	else if (len > BUFSIZE)
  	    len = BUFSIZE;
  	len /= sizeof(xReply);
--- 99,105 ----
  	if (BytesReadable(dpy->fd, (char *) &pend) < 0)
  	    (*_XIOErrorFunction)(dpy);
  	if ((len = pend) < sizeof(xReply))
! 	    return(dpy->qlen);	/* _XFlush can enqueue events */
  	else if (len > BUFSIZE)
  	    len = BUFSIZE;
  	len /= sizeof(xReply);
***************
*** 115,121 ****
  }
  
  /* _XReadEvents - Flush the output queue,
!  * then read as many events as possible and enqueue them
   */
  _XReadEvents(dpy)
  	register Display *dpy;
--- 115,121 ----
  }
  
  /* _XReadEvents - Flush the output queue,
!  * then read as many events as possible (but at least 1) and enqueue them
   */
  _XReadEvents(dpy)
  	register Display *dpy;
***************
*** 124,131 ****
--- 124,134 ----
  	long pend_not_register; /* because can't "&" a register variable */
  	register long pend;
  	register xEvent *ev;
+ 	int qlen = dpy->qlen;
  
  	_XFlush (dpy);
+ 	if (qlen != dpy->qlen)
+ 	    return;
  	do {
  	    /* find out how much data can be read */
  	    if (BytesReadable(dpy->fd, (char *) &pend_not_register) < 0)
***************
*** 360,366 ****
      while (newseq < lastseq) {
  	newseq += 0x10000;
  	if (newseq > dpy->request) {
! 	    (void) fprintf(stderr, "sequence lost!\n");
  	    newseq -= 0x10000;
  	    break;
  	}
--- 363,372 ----
      while (newseq < lastseq) {
  	newseq += 0x10000;
  	if (newseq > dpy->request) {
! 	    (void) fprintf (stderr, 
! 	    "Xlib:  sequence lost (0x%lx > 0x%lx) in reply type 0x%x!\n",
! 	                           newseq, dpy->request, 
! 				   (unsigned int) rep->type);
  	    newseq -= 0x10000;
  	    break;
  	}
***************
*** 1011,1017 ****
      XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
  	mesg, BUFSIZ);
      (void) fprintf(stderr, mesg, dpy->request);
!     fputs("\n  ", stderr);
      if (event->error_code == BadImplementation) return 0;
      exit(1);
      /*NOTREACHED*/
--- 1017,1023 ----
      XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
  	mesg, BUFSIZ);
      (void) fprintf(stderr, mesg, dpy->request);
!     fputs("\n", stderr);
      if (event->error_code == BadImplementation) return 0;
      exit(1);
      /*NOTREACHED*/