bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#9087: Crash reading from minibuffer with icomplete-mode


From: Eli Zaretskii
Subject: bug#9087: Crash reading from minibuffer with icomplete-mode
Date: Sat, 07 Jan 2012 16:59:18 +0200

> Date: Sat, 07 Jan 2012 14:57:31 +0100
> From: martin rudalics <rudalics@gmx.at>
> CC: monnier@iro.umontreal.ca, jasonr@gnu.org, claudio.bley@gmail.com, 
>  lekktu@gmail.com, 9087@debbugs.gnu.org
> 
>  >>  > You can verify yourself that, in Emacs without
>  >>  > the patch I sent, typing C-g when triggerbug.el says "now!" does not
>  >>  > cause a crash, but a "Quit", albeit a slightly (by 1-2 seconds on my
>  >>  > box) delayed one.
>  >>
>  >> Because `signal' resets immediate_quit to zero?
>  >
>  > You mean, as explanation of the delay?
> 
> No.  I meant as an explanation of the non-crash.
> 
>  > No, I don't think so.  I think
>  > Emacs simply doesn't see C-g until the lengthy calculation is over.
> 
> Likely.  But where is C-g treated differently from other input?

Here:

  static void
  post_character_message (HWND hwnd, UINT msg,
                          WPARAM wParam, LPARAM lParam,
                          DWORD modifiers)
  {
    W32Msg wmsg;

    wmsg.dwModifiers = modifiers;

    /* Detect quit_char and set quit-flag directly.  Note that we
       still need to post a message to ensure the main thread will be
       woken up if blocked in sys_select, but we do NOT want to post
       the quit_char message itself (because it will usually be as if
       the user had typed quit_char twice).  Instead, we post a dummy
       message that has no particular effect. */
    {
      int c = wParam;
      if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
        c = make_ctrl_char (c) & 0377;
      if (c == quit_char
          || (wmsg.dwModifiers == 0 &&
              w32_quit_key && wParam == w32_quit_key))
        {
          Vquit_flag = Qt;

          /* The choice of message is somewhat arbitrary, as long as
             the main thread handler just ignores it. */
          msg = WM_NULL;

          /* Interrupt any blocking system calls.  */
          signal_quit ();

          /* As a safety precaution, forcibly complete any deferred
             messages.  This is a kludge, but I don't see any particularly
             clean way to handle the situation where a deferred message is
             "dropped" in the lisp thread, and will thus never be
             completed, eg. by the user trying to activate the menubar
             when the lisp thread is busy, and then typing C-g when the
             menubar doesn't open promptly (with the result that the
             menubar never responds at all because the deferred
             WM_INITMENU message is never completed).  Another problem
             situation is when the lisp thread calls SendMessage (to send
             a window manager command) when a message has been deferred;
             the lisp thread gets blocked indefinitely waiting for the
             deferred message to be completed, which itself is waiting for
             the lisp thread to respond.

             Note that we don't want to block the input thread waiting for
             a response from the lisp thread (although that would at least
             solve the deadlock problem above), because we want to be able
             to receive C-g to interrupt the lisp thread.  */
          cancel_all_deferred_msgs ();
        }
      else
        signal_user_input ();
    }

    my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
  }

And signal_user_input then does:

  static void
  signal_user_input (void)
  {
    /* Interrupt any lisp that wants to be interrupted by input.  */
    if (!NILP (Vthrow_on_input))
      {
        Vquit_flag = Vthrow_on_input;
        /* If we're inside a function that wants immediate quits,
           do it now.  */
        if (immediate_quit && NILP (Vinhibit_quit))
          {
            immediate_quit = 0;
            QUIT;
          }
      }
  }

This call to QUIT is the problem, because this code runs in a
different thread than the main Lisp thread, the one that set up the
setjmp point to which we longjmp when we throw to top level.  So it
unwinds the wrong stack.

By contrast, C-g does not call signal_user_input to be called, see
above.  So it avoids this fate.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]