> 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 wrote: > > From: Paul Pogonyshev > > 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. >