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?

1
  • 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 3, 2014 at 4:41

4 Answers 4

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
8
  • 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). Feb 28, 2016 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. May 18, 2016 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, 2016 at 14:32
  • 4
    On my system the oneliner can be simplified to ‘killall -USR2 emacs’ (avoid if you have multiple Emacs processes of course).
    – YoungFrog
    Mar 4, 2017 at 7:20
  • 1
    Recommend htop (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 8, 2018 at 9: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.

3
  • You might have to hit C-g several times: C-g C-g C-g.
    – Drew
    Oct 3, 2014 at 4:37
  • @Drew I've also noticed that hitting it several times is necessary. Do you know why? Oct 3, 2014 at 8:21
  • 3
    Yes. See the Emacs manual, node Quitting. How did I find that? C-h r i, then type "C-g" and hit RET.
    – Drew
    Oct 3, 2014 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.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.