Subject: bug#13864: 24.3.50; emacsclient -t loops when connected to emacs server running in X11

From: Eli Zaretskii <[email-masked]>
Date: Mon, 25 Mar 2013 12:56:06 +0200

> From: [email-masked] (Ashish SHUKLA)
> Cc: [email-masked]
> Date: Mon, 25 Mar 2013 14:58:08 +0530
> 
> >  (gdb) break dispnew.c:2623 if vpos == 5
> 
> s/vpos/row/ I guess

Yes, sorry.

> Please refer to the attached gdb output with annotations prefixed with '=====> '.

OK, the reason for constant redrawing of the emacsclient TTY frame is
that Emacs thinks that frame is "garbaged" (i.e. its display is
completely outdated and should be redrawn):

  Hardware watchpoint 6: ((struct glyph_row *) 0x196e500)->enabled_p

  Old value = 1
  New value = 0
  clear_glyph_matrix_rows (matrix=0x1825f00, start=5, end=28) at dispnew.c:728
  728	  for (; start < end; ++start)
  #0  clear_glyph_matrix_rows (matrix=0x1825f00, start=5, end=28) at dispnew.c:728
  #1  0x0000000000417028 in clear_glyph_matrix (matrix=0x1825f00) at dispnew.c:747
  #2  0x00000000004175bc in clear_current_matrices (f=0x117ac48) at dispnew.c:795
  #3  0x000000000044c348 in clear_garbaged_frames () at xdisp.c:10611
  #4  0x0000000000450de9 in redisplay_internal () at xdisp.c:12925

The function clear_garbaged_frames does this:

      FOR_EACH_FRAME (tail, frame)
	{
	  struct frame *f = XFRAME (frame);

	  if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f)) <<<<<<<<<
	    {
	      if (f->resized_p)
		{
		  redraw_frame (f);
		  f->force_flush_display_p = 1;
		}
	      clear_current_matrices (f); <<<<<<<<<<<<<<<<<<<<<<<<<<<
	      changed_count++;
	      f->garbaged = 0;
	      f->resized_p = 0;
	    }
	}

And the call to clear_current_matrices invalidates the record of
what's currently displayed on the TTY frame, and therefore causes
constant redrawing of that frame.

So the question now is: which code sets the frame's 'garbaged' flag?
To find out, do this in GDB:

 (gdb) tbreak dispnew.c:4861 if vpos == 5
 (gdb) c

The breakpoint is here:

      else
	/* Make sure we are in the right row, otherwise cursor movement
	   with cmgoto might use `ch' in the wrong row.  */
	cursor_to (f, vpos, 0);

      make_current (desired_matrix, current_matrix, vpos); <<<<<<<<<<<<<<<<
      return;
    }

Note that the breakpoint is temporary ("tbreak"), so it will only
break once.  This is to avoid hitting it again, after you set the
watchpoint below, because we only need this breakpoint to find out the
address of the TTY frame structure, whose 'garbaged' flag we want to
watch.

When this breakpoint breaks, type these commands:

 (gdb) p f
 $1 = (struct frame *) 0x12345678
 (gdb) watch ((struct frame *) 0x12345678)->garbaged
 (gdb) commands
  > if ((struct frame *) 0x12345678)->garbaged == 1
  >   bt
  > end
  > continue
 (gdb)

Again, the value of f will be different in your case; use whatever GDB
shows in your case for the following 'watch' command.

Now do whatever is needed to cause Emacs flicker, and the backtrace
from the watchpoint should show who sets the garbaged flag of the TTY
frame.

Thanks.