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

From: Eli Zaretskii <[email-masked]>
Date: Sun, 24 Mar 2013 21:54:04 +0200

> From: [email-masked] (Ashish SHUKLA)
> Cc: [email-masked]
> Date: Fri, 22 Mar 2013 18:14:22 +0530
> 
> > That's strange, I'm probably missing something.  Not terribly
> > important (it's tangential to the issue I'm hunting with your GDB
> > collected data), but could you give me a recipe to cause such a
> > tooltip in the xterm frame by some key-press?
> 
> Sure, you set a breakpoint to some function which gets invoked as 'emacsclient
> -t' starts, like update_frame_line, but forgot to add 'cont' to the list of
> commands. And then you forgot that you didn't add 'cont' and starts
> 'emacsclient -t' and start typing (like some arrow key) without noticing that
> 'emacsclient' frame has yet to appear on the screen. Now look at gdb window,
> breakpoint must have it, do 'cont' there so that emacsclient starts, and now
> you'll see some characters in buffer, with "End of buffer" message in
> minibuffer (tooltip).

But the text I saw was different: it was the text of a tooltip for
mouse-sensitive portions of the mode line:

 Major mode, mouse-1: Display major mode menu, mouse-2: Show help for major mode

Strange.  Anyway, you can forget this for now; if this is important,
we'll get back to it later.

> FTR, I'm still running r111924 for this debugging to avoid adding more
> variables.

OK, that's good.

> > Once you are set up in GDB, make Emacs flicker, and collect the data
> > printed by GDB.  The goal of these breakpoints is to see which code is
> > involved in the flickering situation, and which parts of it are
> > actually writing to the screen.
> 
> The output is attached

Thanks.  Here's what flickering looks like:

  Breakpoint 4, update_frame_line (f=0x12efd88, vpos=0) at dispnew.c:4845
  4845		  write_glyphs (f, nbody, nlen);
  $36808 = 0
  $36809 = 239
  $36810 = 239

  Breakpoint 6, update_frame_line (f=0x12efd88, vpos=0) at dispnew.c:4859
  4859		cursor_to (f, vpos, 0);
  $36811 = 0

  Breakpoint 4, update_frame_line (f=0x12efd88, vpos=1) at dispnew.c:4845
  4845		  write_glyphs (f, nbody, nlen);
  $36812 = 1
  $36813 = 239
  $36814 = 239

  Breakpoint 6, update_frame_line (f=0x12efd88, vpos=1) at dispnew.c:4859
  4859		cursor_to (f, vpos, 0);
  $36815 = 1

  Breakpoint 4, update_frame_line (f=0x12efd88, vpos=2) at dispnew.c:4845
  4845		  write_glyphs (f, nbody, nlen);
  $36816 = 2
  $36817 = 239
  $36818 = 239

  Breakpoint 6, update_frame_line (f=0x12efd88, vpos=2) at dispnew.c:4859
  4859		cursor_to (f, vpos, 0);
  $36819 = 2

  Breakpoint 4, update_frame_line (f=0x12efd88, vpos=3) at dispnew.c:4845
  4845		  write_glyphs (f, nbody, nlen);
  $36820 = 3
  $36821 = 239
  $36822 = 239

  Breakpoint 6, update_frame_line (f=0x12efd88, vpos=3) at dispnew.c:4859
  4859		cursor_to (f, vpos, 0);
  $36823 = 3

  Breakpoint 5, update_frame_line (f=0x12efd88, vpos=4) at dispnew.c:4854
  4854	          clear_end_of_line (f, FRAME_TOTAL_COLS (f));
  $36824 = 4
  $36825 = 239
  $36826 = 0

  Breakpoint 4, update_frame_line (f=0x12efd88, vpos=5) at dispnew.c:4845
  4845		  write_glyphs (f, nbody, nlen);
  $36827 = 5
  $36828 = 239
  $36829 = 27

  Breakpoint 5, update_frame_line (f=0x12efd88, vpos=5) at dispnew.c:4854
  4854	          clear_end_of_line (f, FRAME_TOTAL_COLS (f));
  $36830 = 5
  $36831 = 239
  $36832 = 27

  Breakpoint 5, update_frame_line (f=0x12efd88, vpos=6) at dispnew.c:4854
  4854	          clear_end_of_line (f, FRAME_TOTAL_COLS (f));
  $36833 = 6
  $36834 = 239
  $36835 = 0

  Breakpoint 5, update_frame_line (f=0x12efd88, vpos=7) at dispnew.c:4854
  4854	          clear_end_of_line (f, FRAME_TOTAL_COLS (f));
  $36836 = 7
  $36837 = 239
  $36838 = 0

  Breakpoint 5, update_frame_line (f=0x12efd88, vpos=8) at dispnew.c:4854
  4854	          clear_end_of_line (f, FRAME_TOTAL_COLS (f));
  $36839 = 8
  $36840 = 239
  $36841 = 0

etc., for all the lines of the TTY frame (note the vpos values going
from 0 to 43, for 43-line frame).  For each line on that frame, Emacs
first writes the characters, if any, of the text on that line, and
then clears to the end of the line.

This code is here:

  /* If display line has unknown contents, write the whole line.  */
  if (must_write_whole_line_p)
    {
      [...]
      /* Write the contents of the desired line.  */
      if (nlen)
	{
          cursor_to (f, vpos, 0);
	  write_glyphs (f, nbody, nlen);
	}

      /* Don't call clear_end_of_line if we already wrote the whole
	 line.  The cursor will not be at the right margin in that
	 case but in the line below.  */
      if (nlen < FRAME_TOTAL_COLS (f))
	{
	  cursor_to (f, vpos, nlen);
          clear_end_of_line (f, FRAME_TOTAL_COLS (f));
	}
      else

and must_write_whole_line_p is computed like this:

  /* Current row not enabled means it has unknown contents.  We must
     write the whole desired line in that case.  */
  must_write_whole_line_p = !current_row->enabled_p;

IOW, the problem that causes continuous redrawing of the entire frame
is that every single line ("glyph row") of that frame is marked as
"not enabled" (i.e., invalid) in the current glyph matrix, which is a
structure that describes what is currently on the glass.

The current matrix has every one of its lines marked as valid at the
end of each redisplay cycle.  So the question now is: which code
resets those enabled_p flags of every glyph row in the current matrix,
and thus defeats the code that avoids redrawing the same contents?

To answer that, let's put a watchpoint at the enabled_p flag of one of
the glyph rows.  Like this:

 (gdb) break dispnew.c:2623 if vpos == 5

This breakpoint is inside the make_current function:

  static void
  make_current (struct glyph_matrix *desired_matrix, struct glyph_matrix *current_matrix, int row)
  {
    struct glyph_row *current_row = MATRIX_ROW (current_matrix, row);
    struct glyph_row *desired_row = MATRIX_ROW (desired_matrix, row);
    bool mouse_face_p = current_row->mouse_face_p;

    /* Do current_row = desired_row.  This exchanges glyph pointers
       between both rows, and does a structure assignment otherwise.  */
    assign_row (current_row, desired_row);

    /* Enable current_row to mark it as valid.  */
    current_row->enabled_p = 1;
    current_row->mouse_face_p = mouse_face_p;  <<<<<<<<<<<<<<<<<<<<<<

The choice of the line (5) is arbitrary.  Then wait until the
breakpoint breaks, and do this:

 (gdb) p current_row
 $1 = (struct glyph_row *) 0x37e1158

(The address will be different in your case.)  Now use that address to
put a hardware watchpoint on the enabled_p flag of that glyph row, and
continue the program:

 (gdb) watch ((struct glyph_row *) 0x37e1158)->enabled_p
 (gdb) c

Now do whatever it takes to cause the flicker, and wait for the
watchpoint to trigger, it should say something like

 Hardware watchpoint 5: ((struct glyph_row *) 0x37e1158)->enabled_p

 Old value = 1
 New value = 0

and will next show the source line which modified the value.  Then
type

 (gdb) bt

and let it continue

 (gdb) c

Do this several times, each time waiting until the watchpoint
triggers, and displaying the backtrace.  That should point towards the
code which resets these flags and causes excessive re-drawing.

Thanks.