all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: "Clément Pit--Claudel" <clement.pit@gmail.com>
To: emacs-devel@gnu.org
Subject: Re: How can I rethrow an error after recording a backtrace?
Date: Thu, 4 Aug 2016 22:34:23 -0400	[thread overview]
Message-ID: <bc8beba2-6671-75f4-936e-a2522e8ffdff@gmail.com> (raw)
In-Reply-To: <53ca9864-3a3b-8406-65c9-8458d0512299@gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 5479 bytes --]

Some notes:

* I should really have asked "how can I capture multiple errors on Emacs server?". It turns out that the rethrowing is pretty irrelevant, as it just seems that the number of non-macro input events stays 0 on a --daemon server.

* In light of this, is this comment actually true?

  /* The value of num_nonmacro_input_events as of the last time we
     started to enter the debugger.  If we decide to enter the debugger
     again when this is still equal to num_nonmacro_input_events, then we
     know that the debugger itself has an error, and we should just
     signal the error instead of entering an infinite loop of debugger
     invocations.  */

  What if num_nonmacro_input_events just didn't increase because there were no such events? And thus, is the behavior that I'm seeing a bug? Or is it just a weird aspect of running code on a --daemon server, and I should submit a documentation patch suggesting to `(cl-incf num-nonmacro-input-events)'?

Cheers,
Clément.

On 2016-08-04 22:12, Clément Pit--Claudel wrote:
> Hey emacs-devel,
> 
> The Emacs server doesn't print backtraces, so I'm trying to get these backtraces myself and return them to the server.  After some exploration, I found about the debugger variable, and realized that I could actually force code to break into the debugger regardless of handlers using debug-on-signal. So far so good. Then I wrote the following "debugger"
> 
>     (defun my-handle-error (&rest args)
>       (let (;; Prevent recursive error catching
>             (debugger #'debug)
>             (debug-on-quit nil)
>             (debug-on-error nil)
>             (debug-on-signal nil))
>         (pcase args
>           (`(exit ,retv) retv)
>           (`(error ,error-args)
>            (setq saved-backtrace (with-output-to-string (backtrace)))
>            (signal (car error-args) (cdr error-args))))))
> 
> And then I called my code as follows:
> 
>     (let* (;; Make sure that we'll intercept all errors
>            (debug-on-quit t)
>            (debug-on-error t)
>            (debug-on-signal t)
>            (debug-ignored-errors nil)
>            ;; Make sure debugger has room to execute
>            (max-specpdl-size (+ 50 max-specpdl-size))
>            (max-lisp-eval-depth (+ 50 max-lisp-eval-depth))
>            ;; Register ourselves as the debugger
>            (debugger #'my-handle-error))
>       (my code here))
> 
> This was in part inspired by similar code in allout-widgets.el (although I think that code never worked, since it calls signal with a non-list second argument).
> 
> When running on an emacs server, though, this code doesn't work. That is, it works fine the first time, but not on further invocations; so I stepped through the code in GDB, and I understood that the issue was here:
> 
>     if (
>         /* Don't try to run the debugger with interrupts blocked.
>        The editing loop would return anyway.  */
>         ! input_blocked_p ()
>         && NILP (Vinhibit_debugger)
>         /* Does user want to enter debugger for this kind of error?  */
>         && (EQ (sig, Qquit)
>         ? debug_on_quit
>         : wants_debugger (Vdebug_on_error, conditions))
>         && ! skip_debugger (conditions, combined_data)
>         /* RMS: What's this for?  */
>         && when_entered_debugger < num_nonmacro_input_events)
>       {
>         call_debugger (list2 (Qerror, combined_data));
>         return 1;
>       }
> 
> (in maybe_call_debugger). The first time around the debugger is called, but not the second time, because the `when_entered_debugger < num_nonmacro_input_events` is false (on the first round it evaluates to -1 < 0, and on the second one to 0 < 0). This reason for this clause was explained when this code was written back in 1991:
> 
>     /* The value of num_nonmacro_input_events as of the last time we
>        started to enter the debugger.  If we decide to enter the debugger
>        again when this is still equal to num_nonmacro_input_events, then we
>        know that the debugger itself has an error, and we should just
>        signal the error instead of entering an infinite loop of debugger
>        invocations.  */
> 
>     static EMACS_INT when_entered_debugger;
> 
> The problem is that I'm running this code using emacsclient --eval '(error "abc")', and so the num_nonmacro_input_events value never increases. I "fixed" it this way:
> 
>     (defun my-handle-error (&rest args)
>       (let (;; Prevent recursive error catching
>             (debugger #'debug)
>             (debug-on-quit nil)
>             (debug-on-error nil)
>             (debug-on-signal nil))
>         ;; HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK ;;
>         (setq num-nonmacro-input-events (1+ num-nonmacro-input-events))
>         ;; HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK ;;
>         (pcase args
>           (`(exit ,retv) retv)
>           (`(error ,error-args)
>            (setq saved-backtrace (with-output-to-string (backtrace)))
>            (signal (car error-args) (cdr error-args))))))
> 
> Is this going to have horrible consequences? If it is, could someone more experienced point me to how I am supposed to capture a backtrace and then rethrow an error? I can provide a full example if anyone wants to experiment and finds this description incomplete.
> 
> Cheers,
> Clément.
> 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

  parent reply	other threads:[~2016-08-05  2:34 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-08-05  2:12 How can I rethrow an error after recording a backtrace? Clément Pit--Claudel
2016-08-05  2:23 ` Stefan Monnier
2016-08-05  9:40   ` Clément Pit--Claudel
2016-08-06  2:11     ` Stefan Monnier
2016-08-06 10:03       ` Eli Zaretskii
2016-08-06 13:29         ` Stefan Monnier
2016-08-05  2:34 ` Clément Pit--Claudel [this message]
2016-08-05  6:12   ` Eli Zaretskii
     [not found]     ` <73dc7988-7b41-385d-1083-6a6fa4bfbd91@gmail.com>
2016-08-05 13:40       ` Eli Zaretskii
2016-08-05 15:38         ` Clément Pit--Claudel
2016-08-06 10:02           ` Eli Zaretskii
2016-08-06 15:24             ` Clément Pit--Claudel
2016-08-06 15:31               ` Eli Zaretskii
2016-08-06 15:49                 ` Clément Pit--Claudel
2016-08-06 17:38                   ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bc8beba2-6671-75f4-936e-a2522e8ffdff@gmail.com \
    --to=clement.pit@gmail.com \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.