Subject: Re: bug#75056: 31.0.50; tty-child-frames with server / multiple clients possible hangs

From: Gerd Möllmann <[email-masked]>
Date: Tue, 28 Jan 2025 20:03:48 +0100

martin rudalics <[email-masked]> writes:

>>> But maybe it's only the
>>>
>>>    eassert (FRAME_VISIBLE_P (root));
>>>
>>> assertion there that would have to be adapted.
>>
>> I seem to have missed that, sorry I'm bit distracted ATM. Or was that
>> the one in combine_updates_for_frame with multi-tty? I think I committed
>> a workaround/fix for that to master. Also for the root frame always
>> returning t in frame-visible-p.
>
> Forget it.  I was in the wrong branch.  Just to verify one thing: When
> in a tty frame I do
>
> (make-frame '((window-system . x)))
>
> move to the graphical and back to the tty frame	I get a crash like
>
> #0  terminate_due_to_signal (sig=6, backtrace_limit=2147483647) at ../../src/emacs.c:432
> #1 0x000000000069abc9 in die (msg=0x7e0a28 "!FRAME_WINDOW_P (XFRAME
> (w->frame))", file=0x7e029f "../../src/dispnew.c", line=3193) at
> ../../src/alloc.c:7989
> #2  0x000000000042539b in window_to_frame_hpos (w=0xbcccb98, hpos=0) at ../../src/dispnew.c:3193
> #3  0x000000000042b9e5 in tty_set_cursor () at ../../src/dispnew.c:5669
> #4 0x000000000042bba5 in write_matrix (f=0xb83fd40,
> inhibit_id_p=false, set_cursor_p=true, updating_menu_p=false) at

Hm, new fun with multi-tty. I can see the following

We're doing a normal update of a tty root frame. At the end of writing
to the terminal (write_matrix), we try to set the cursor
(tty_set_cursor). tty_set_cursor begins

dispnew.c:
 5620 static void
 5621 tty_set_cursor (void)
 5622 {
 5623   struct frame *f = SELECTED_FRAME ();

and further down, when the cursor is not in the echo area, and so on

dispnew.c:
 5685       /* We have only one cursor on terminal frames.  Use it to
 5686          display the cursor of the selected window.  */
 5687       struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
 5688       if (w->cursor.vpos >= 0
 5689           /* The cursor vpos may be temporarily out of bounds
 5690              in the following situation:  There is one window,
 5691              with the cursor in the lower half of it.  The window
 5692              is split, and a message causes a redisplay before
 5693              a new cursor position has been computed.  */
 5694           && w->cursor.vpos < WINDOW_TOTAL_LINES (w))
 5695         {
 5696           int x = WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos);
 5697           int y = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos);

Means that the selected frame at the time of the update is the X frame.

The redisplay happens from command_loop_1 which tries to get input:

> #8  0x0000000000480825 in redisplay () at ../../src/xdisp.c:16668
> #9 0x00000000005f68ac in read_char (commandflag=1,
> map=XIL(0x7f4b28c2f623), prev_event=XIL(0),
> used_mouse_menu=0x7fff72a5a8ef, end_time=0x0) at
> ../../src/keyboard.c:2672
> #10 0x000000000060a7da in read_key_sequence (keybuf=0x7fff72a5aaa0,
> prompt=XIL(0), dont_downcase_last=false, can_return_switch_frame=true,
> fix_current_buffer=true, prevent_redisplay=false,
> disable_text_conversion_p=false) at ../../src/keyboard.c:10746
> #11 0x00000000005f2c2d in command_loop_1 () at ../../src/keyboard.c:1424

I would say something in the switching to X and then back to tty is not
working, and the culprit could be do_switch_frame.

But at the same time this would be strange because combine_udpates has

frame.c:
 1833   /* After setting `selected_frame`, we're temporarily in an inconsistent
 1834      state where (selected-window) != (frame-selected-window).  Until this
 1835      invariant is restored we should be very careful not to run ELisp code.
 1836      (bug#58343)  */
 1837   selected_frame = frame;
 1838 

So it should have set the selected_frame to the tty frame. Except when
another switch-frame event or a call to select-frame happens in the
other direction, after a do_switch_frame to the tty frame.

Which is a long way of saying I don't know what's happening.

Maybe you could add "fprintf (stderr" in do_switch_frame in line 1837 so
that one could see if that hypothesis holds water?