62

I am using mew for my e-mail. I need to use TLS with my email provider for SMTP. However, when I try to invoke that, Emacs freezes.

I would like to take this opportunity to learn more about Emacs packages. How would I go about debugging this issue? Is there some kind of built-in debugger, like in Common Lisp? Could I use logging?

Svante
  • 721
  • 5
  • 7
  • 3
    How do you "invoke that"? If it is by using an Emacs command that is defined in Lisp then you can (1) load the source code that defines the command, (2) use `M-x debug-on-entry THE-COMMAND`, then step through the debugger using `d` (or sometimes `c` to skip through some steps). Keep the source code open in another frame, so you can follow what the debugger is doing. Report what you see here or, if you think it suggests an Emacs bug, using `M-x report-emacs-bug`. – Drew Oct 03 '14 at 04:41

4 Answers4

61

Before resorting to gdb, if you're using a Unix-y operating system, you can try sending SIGUSR2 to the Emacs process, like documented in the DEBUG file mentioned in the other answer.

$ kill -SIGUSR2 <emacs_pid_goes_here>

This will make Emacs attempt to break out of its current loop into the Lisp debugger.

Or use this one liner without typing emacs pid manually:

$ ps aux | grep -ie emacs | grep -v grep | awk '{print $2}' | xargs kill -SIGUSR2

Alternatively, if killall is available:

$ killall -USR2 emacs
YoungFrog
  • 3,496
  • 15
  • 27
Dmitry
  • 3,508
  • 15
  • 20
  • 1
    Had to do it twice (well, I could have waited more than 1 second before retrying :-). Anyway, it pinpointed the problem (a font-lock processing too slow for a long line). – Stéphane Gourichon Feb 28 '16 at 15:18
  • font-lock is known to hang Emacs -- if a matcher trigger but doesn't move the point forward, it will retrigger forever. – Lindydancer May 18 '16 at 11:13
  • 1
    wow, that was amazing. Still not sure what's causing my issue but that trick is a lifesaver, thank you! – Matt Dec 23 '16 at 14:32
  • Work for me even while emacs was taking no input. – Pieter Müller Feb 13 '17 at 12:34
  • 4
    On my system the oneliner can be simplified to ‘killall -USR2 emacs’ (avoid if you have multiple Emacs processes of course). – YoungFrog Mar 04 '17 at 07:20
  • @YoungFrog Good idea. Please suggest it in an edit of the "alternative one-liner". – Dmitry Mar 04 '17 at 11:19
  • Minor nitpick, you can avoid `grep`, because `awk` already knows how to search, e.g. `awk '/emacs/ && !/grep/ {print $2}'`. And to avoid both grep and awk, use `ps -C emacs -o pid=`. Although, this might work only with procps. – Olaf Dietsche Oct 09 '17 at 15:54
  • 1
    Recommend htop (https://en.wikipedia.org/wiki/Htop) for this. `/` to search for `emacs` and `k` to send the signal. Activity Monitor on a Mac can also do it (from the menu: View | Send Signal to Process). – Lassi Sep 08 '18 at 09:59
43

If the freeze goes away when you hit C-g, then you can use the built-in debugger. Type M-x toggle-debug-on-quit before sending the message, hit C-g when it freezes, and inspect the *Backtrace* buffer that comes up.

If C-g doesn't help, then the freeze probably happens in the C code, and you'll need to use an external debugger such as gdb. Hit C-h C-d to see the DEBUG file which gives some hints about how to do that. (You can also read the DEBUG file in the Emacs repository web interface.) This answer goes into more details about how to use gdb with Emacs.

legoscia
  • 6,012
  • 29
  • 54
  • You might have to hit `C-g` several times: `C-g C-g C-g`. – Drew Oct 03 '14 at 04:37
  • @Drew I've also noticed that hitting it several times is necessary. Do you know why? – Wilfred Hughes Oct 03 '14 at 08:21
  • 3
    Yes. See the [Emacs manual, node `Quitting`](https://www.gnu.org/software/emacs/manual/html_node/emacs/Quitting.html#Quitting). How did I find that? `C-h r i`, then type "C-g" and hit `RET`. – Drew Oct 03 '14 at 15:12
4

None of the other answers work for me. When my emacs hangs, I can only bring it back by killing and restarting it, but then after a while it hangs again. So there has to be a way to find out the reason.

One of the method that I used was to attach it to gdb. When emacs hangs, I executed the following command to attach gdb to Emacs:

sudo gdb attach 967

967 is the PID of emacs(which can be found by running ps -aux | grep emacs). When you see the (gdb) prompt, input bt full to get the backtrace. For example, when my emacs hangs, my backtrace is:

    (gdb) bt full
    #0  0x00007f569cd2046f in poll () at /usr/lib/libc.so.6
    #1  0x00007f569dfd263b in  () at /usr/lib/libxcb.so.1
    #2  0x00007f569dfd437b in xcb_wait_for_event () at /usr/lib/libxcb.so.1
    #3  0x00007f569e038209 in _XReadEvents () at /usr/lib/libX11.so.6
    #4  0x00007f569e01f396 in XIfEvent () at /usr/lib/libX11.so.6
    #5  0x00007f569e068ca0 in  () at /usr/lib/libX11.so.6
    #6  0x00007f569e0699d2 in  () at /usr/lib/libX11.so.6
    #7  0x00007f569e069c6c in _XimRead () at /usr/lib/libX11.so.6
    #8  0x00007f569e0583ce in  () at /usr/lib/libX11.so.6
    #9  0x00007f569e045955 in XSetICValues () at /usr/lib/libX11.so.6
    #10 0x0000561ace6df9b3 in  ()
    #11 0x0000561ace6627a7 in  ()
    #12 0x0000561ace61e5a5 in  ()
    #13 0x0000561ace61eb33 in  ()
    #14 0x0000561ace61ffdb in  ()
    #15 0x0000561ace6201fb in  ()
    #16 0x0000561ace659154 in  ()
    #17 0x0000561ace65a6b5 in  ()
    #18 0x0000561ace7054ff in  ()
    #19 0x0000561ace7bc9e0 in  ()
    #20 0x0000561ace6210d3 in  ()
    #21 0x0000561ace707efd in  ()
    #22 0x0000561ace708928 in  ()
    #23 0x0000561ace70a06f in  ()
    #24 0x0000561ace7779e7 in  ()
    #25 0x0000561ace6fae65 in  ()
    #26 0x0000561ace777942 in  ()
    #27 0x0000561ace6fadfd in  ()
    #28 0x0000561ace70040b in  ()
    #29 0x0000561ace700734 in  ()
    #30 0x0000561ace616de1 in  ()
    #31 0x00007f569cc53152 in __libc_start_main () at /usr/lib/libc.so.6
    #32 0x0000561ace61753e in  ()

Something seems to be wrong with xcb, then I googled for xcb_wait_for_event emacs and found this post which solves my problem after I followed its solution: https://gitlab.freedesktop.org/xorg/lib/libx11/-/issues/35

I'm not a expert in gdb or emacs or c, but at least gdb gave me a clue about what should I look at. I suggest you try do the same if neither C-g nor kill -SIGUSR2 works for you.

Searene
  • 479
  • 2
  • 14
3

When nothing else works besides a hard kill of Emacs, I finally developed something that utilizes a little known feature of Emacs, what I call special events callbacks. It works by telling Emacs to send itself a pkill -USR2 emacs and then "catch" the event to execute arbitrary elisp which you couldn't otherwise execute due to, say in my case, a runaway timer that is making keyboard input impossible. The novelty of this technique is that the key binding registers a signal event handler rather than a keystroke:

    (defun spray-mode-usr2-handler ()
      "Handle case where spray mode timer is left running when the w3m buffer it is spraying is killed inadvertently instead of stopping spray mode first and won't
respond to C-g or other mechanisms. This will stop spray mode via an
external signal: pkill -USR2 emacs."
      (interactive)
      ;; arbitrary elisp you wish to execute:
      (message "Got USR2 signal")
      (spray-stop)) 
    (global-set-key [signal usr2] 'spray-mode-usr2-handler)
    ;;               ^ here we register the event handler that will automatically be called when send-usr2-signal-to-emacs fires

    (defun send-usr2-signal-to-emacs ()
      "Send pkill -USR2 emacs rather than having to do it at the command line."
      (interactive)
      (signal-process (emacs-pid) 'sigusr2))
    (global-set-key (kbd "M-G") 'send-usr2-signal-to-emacs)

Credit for the first half of the solution came to my attention thanks to @PythonNut: https://emacs.stackexchange.com/a/7893/8353

References: https://www.gnu.org/software/emacs/manual/html_node/elisp/Misc-Events.html#Misc-Events https://www.gnu.org/software/emacs/manual/html_node/elisp/Event-Examples.html#Event-Examples

Joe
  • 541
  • 3
  • 14