unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* graceful shutdown of non-interactive Elisp program
@ 2020-06-13 21:42 Paul Pogonyshev
  2020-06-13 22:59 ` Joost Kremers
  2020-06-14 15:01 ` Eli Zaretskii
  0 siblings, 2 replies; 4+ messages in thread
From: Paul Pogonyshev @ 2020-06-13 21:42 UTC (permalink / raw)
  To: Emacs developers

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

Hi,

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'.

Is that correct, or am I missing something here?

Paul

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

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: graceful shutdown of non-interactive Elisp program
  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
  1 sibling, 0 replies; 4+ messages in thread
From: Joost Kremers @ 2020-06-13 22:59 UTC (permalink / raw)
  To: emacs-devel


On Sat, Jun 13 2020, Paul Pogonyshev wrote:
> 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.

What do you mean "constantly modifying `kill-emacs-hook'"? You 
just add a function to it when your program starts and if it's 
shut down before Emacs is killed, you remove the function again. 
Or leave it, if it doesn't do any harm.



-- 
Joost Kremers
Life has its moments



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: graceful shutdown of non-interactive Elisp program
  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
  1 sibling, 1 reply; 4+ messages in thread
From: Eli Zaretskii @ 2020-06-14 15:01 UTC (permalink / raw)
  To: Paul Pogonyshev; +Cc: emacs-devel

> 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.



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: graceful shutdown of non-interactive Elisp program
  2020-06-14 15:01 ` Eli Zaretskii
@ 2020-06-14 16:47   ` Paul Pogonyshev
  0 siblings, 0 replies; 4+ messages in thread
From: Paul Pogonyshev @ 2020-06-14 16:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Emacs developers

[-- 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 --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-06-14 16:47 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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

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).