unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Paul Pogonyshev <pogonyshev@gmail.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: Emacs developers <emacs-devel@gnu.org>
Subject: Re: graceful shutdown of non-interactive Elisp program
Date: Sun, 14 Jun 2020 18:47:26 +0200	[thread overview]
Message-ID: <CAG7Bpar-4xvMmXrnxqZXR9YTDSj6HdhsPHUko2=ZAebqfSDCvA@mail.gmail.com> (raw)
In-Reply-To: <83imft3d55.fsf@gnu.org>

[-- Attachment #1: Type: text/plain, Size: 3791 bytes --]

> If you want to raise an exception from a
> kill-emacs-hook (assuming that you want the unwind-protect forms to do
> something), you can do that from kill-emacs-hook, no?

No, I tried. There is a "shield" at C level that prevents me from passing an
exception from a `kill-emacs-hook' to the "main" code:

$ emacs --batch \
        --eval "(add-hook 'kill-emacs-hook (lambda () (signal
'unwind-the-stack nil)))" \
        --eval "(unwind-protect (while t) (message \"GOING DOWN\"))"

^CError in kill-emacs-hook ((closure (t) nil (signal 'unwind-the-stack
nil))): (unwind-the-stack)

As you see, the exception doesn't succeed in making `unwind-protect'
clause to run.

> And if you had a say in handling SIGINT, what would you do in the
> handler that you cannot do in kill-emacs-hook?

It's not the point of doing something special, it's rather the point of
doing _normal_ cleanup that I expected to do otherwise. Let's say my
program does 20 different, sometimes nested and sometimes not
allocations of external resources that I need to free/close somehow.
If `unwind-protect' was guaranteed to run (even in response to C-c)
I could just do

   (unwind-protect
       (do-something-with-resource-N)
     (free) (resource-N) (code))

twenty times. However, as it stands it looks that I have to do

   (let ((free-resource-N (lambda () (free) (resource-N) (code))))
     (add-hook 'kill-emacs-hook free-resource-N)
     (unwind-protect
         (do-something-with-resource-N)
       (funcall free-resource-N))
     (remove-hook 'kill-emacs-hook free-resource-N))

every time.

Additionally, this won't work if I don't control the code that
allocates/frees the resource, i.e. if it happens to be inside some
external package.

> Also, you mention batch mode, but is it relevant?

No, not really. It's just that in batch mode I was expecting to be in full
control of Emacs "command loop" because I don't share Emacs with any
other code (or at most that code can be seen as a "library" for my
program). In interactive mode it's basically the same.

Paul


On Sun, 14 Jun 2020 at 17:01, Eli Zaretskii <eliz@gnu.org> wrote:

> > From: Paul Pogonyshev <pogonyshev@gmail.com>
> > Date: Sat, 13 Jun 2020 23:42:51 +0200
> >
> > I'm trying to make a Elisp program that is run in a non-interactive
> mode, i.e. essentially as `emacs --batch
> > --load myfile.el'. A normal way to shutdown terminal programs is with
> C-c, which is expected to be "graceful"
> > shutdown, e.g. the program still has a chance to save files etc.
> >
> > However, with Elisp I'm not sure how to achieve that except for
> constantly modifying `kill-emacs-hook', which
> > would be a nightmare from coding perspective.
> >
> > Naively I would expect this print "GOING DOWN" when aborted with C-c:
> >
> >     $ emacs --batch --eval "(unwind-protect (while t) (message \"GOING
> DOWN\"))"
> >
> > For example, Python's handler of SIGINT raises an exception within the
> program, which unwinds the stack
> > as usual and, unless caught, cause program termination after cleaning up
> as expected (e.g. running all
> > `finally' clauses and closing all `with' context managers). However, in
> Elisp, as I understand, there is no way
> > to have a say in handling SIGINT other than adding a function to
> `kill-emacs-hook'.
>
> I don't think I follow.  If you want to raise an exception from a
> kill-emacs-hook (assuming that you want the unwind-protect forms to do
> something), you can do that from kill-emacs-hook, no?
>
> And if you had a say in handling SIGINT, what would you do in the
> handler that you cannot do in kill-emacs-hook?
>
> Also, you mention batch mode, but is it relevant?  That is, are you
> saying that Emacs behaves differently in an interactive session when
> it gets a fatal signal?
>
> I'm confused.
>

[-- Attachment #2: Type: text/html, Size: 5260 bytes --]

      reply	other threads:[~2020-06-14 16:47 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-13 21:42 graceful shutdown of non-interactive Elisp program Paul Pogonyshev
2020-06-13 22:59 ` Joost Kremers
2020-06-14 15:01 ` Eli Zaretskii
2020-06-14 16:47   ` Paul Pogonyshev [this message]

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

  List information: https://www.gnu.org/software/emacs/

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

  git send-email \
    --in-reply-to='CAG7Bpar-4xvMmXrnxqZXR9YTDSj6HdhsPHUko2=ZAebqfSDCvA@mail.gmail.com' \
    --to=pogonyshev@gmail.com \
    --cc=eliz@gnu.org \
    --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 public inbox

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).