summary
What to utter from commandline to cause a running clientless Emacs daemon/server process to gracefully shutdown--i.e., clean up after itself, then exit--without creating additional Emacs processes?
Note that by commandline
, I mean "a shell outside Emacs," not M-x
from within Emacs (hence my question does not duplicate this question), though commandline emacsclient --eval
satisfies requirement.
Note regarding potential answers: if your answer requires some interaction, please make it either
(preferred) in the "same commandline." Not sure if that's the correct usage (please correct if not); what I mean is something like
me@it: ~ $ your --code --here Save modified buffers? [Y/n] Y Active processes exist: kill them all? [Y/n] Y Killing daemon ...
(acceptable) in a TUI Emacs in the same shell as the commandline, like (e.g.)
emacsclient --tty
details
testcase
Suppose one has a clientless emacs
daemon/server process. I know I can kill said process from a (Linux) commandline with (e.g.) kill -9 process#
or pkill -9 emacs
, but that won't allow the process to gracefully shutdown. What I mean:
Let's start with no emacs*
processes:
me@it: ~ $ date ; emacs --version
Sun Oct 8 00:57:18 MST 2017
GNU Emacs 24.4.1
...
FWIW, I'm running this on an up-to-date Debian (currently version=8.9) Linux, hence the somewhat downlevel Emacs. No emacs and no lockfiles (more below):
me@it: ~ $ date ; find ~/.emacs.d/ -name '*lock*'
Sun Oct 8 00:57:37 MST 2017
me@it: ~ $ date ; pgrep -l emacs
Sun Oct 8 00:57:43 MST 2017
Now, start a clientless emacs
daemon/server:
me@it: ~ $ date ; emacs --daemon &
Sun Oct 8 01:00:05 MST 2017
...
...
== omitted lots console spew from startup of my emacs config (Emacs Prelude + some code in ~/.emacs.d/personal/
). Besides that, we can confirm the process still exists with
me@it: ~ $ date ; pgrep -l emacs
Sun Oct 8 01:00:56 MST 2017
29422 emacs
... and, since my config uses desktop, there is now a desktop lockfile (which there was not above):
me@it: ~ $ date ; find ~/.emacs.d/ -name '*lock*'
Sun Oct 8 01:01:01 MST 2017
/home/me/.emacs.d/personal/.emacs.desktop.lock
At this point, I want to tell the daemon/server process to
- cleanup (e.g., delete its desktop lockfile), before ...
- shutdown (e.g., kill its process) without creating additional Emacs processes (clients or servers)
failures
(kill-emacs) and related
The Emacs manual says
To kill Emacs without being prompted about saving, type M-x kill-emacs.
But when I do ...
me@it: ~ $ date ; emacsclient --eval '(kill-emacs)'
Sun Oct 8 01:02:41 MST 2017
me@it: ~ $ date ; pgrep -l emacs
Sun Oct 8 01:02:46 MST 2017
29422 emacs
me@it: ~ $ date ; find ~/.emacs.d/ -name '*lock*'
Sun Oct 8 01:02:53 MST 2017
/home/me/.emacs.d/personal/.emacs.desktop.lock
... there is no change. The good news is, this answer suggests how to actually kill the daemon ...
me@it: ~ $ date ; emacsclient --eval '(let (kill-emacs-hook) (kill-emacs))'
Sun Oct 8 01:03:22 MST 2017
me@it: ~ $ date ; pgrep -l emacs
Sun Oct 8 01:03:26 MST 2017
... the bad news is, (let (kill-emacs-hook) (kill-emacs))
is not graceful:
me@it: ~ $ date ; find ~/.emacs.d/ -name '*lock*'
Sun Oct 8 01:03:50 MST 2017
/home/me/.emacs.d/personal/.emacs.desktop.lock
... i.e., that code is no better than pkill -9 emacs
.
(save-buffers-kill-emacs) and related
izkon suggests using
(defun server-shutdown ()
"Save buffers, Quit, and Shutdown (kill) server"
(interactive)
(save-some-buffers)
(kill-emacs))
which Basil claims is equal to (save-buffers-kill-emacs)
. Let's test:
After I kill all my Emacs process and delete all lockfiles, I can add the above code to a file loaded from my init.el
, and then do
me@it: ~ $ date ; find ~/.emacs.d/ -name '*lock*'
Sun Oct 8 14:08:24 MST 2017
me@it: ~ $ date ; pgrep -l emacs
Sun Oct 8 14:08:33 MST 2017
me@it: ~ $ date ; emacs --daemon &
Sun Oct 8 14:08:49 MST 2017
... console spew follows ...
me@it: ~ $ date ; pgrep -l emacs
Sun Oct 8 14:09:15 MST 2017
6087 emacs
me@it: ~ $ date ; find ~/.emacs.d/ -name '*lock*'
Sun Oct 8 14:09:25 MST 2017
/home/me/.emacs.d/personal/.emacs.desktop.lock
So I have a running daemon. I then do
me@it: ~ $ date ; emacsclient --eval '(server-shutdown)'
Sun Oct 8 14:10:25 MST 2017
me@it: ~ $ date ; pgrep -l emacs
Sun Oct 8 14:10:31 MST 2017
6087 emacs
me@it: ~ $ date ; find ~/.emacs.d/ -name '*lock*'
Sun Oct 8 14:10:33 MST 2017
/home/me/.emacs.d/personal/.emacs.desktop.lock
I.e., no change. However, my results from (save-buffers-kill-emacs)
are somewhat worse:
me@it: ~ $ date ; emacsclient --eval '(save-buffers-kill-emacs)'
Sun Oct 8 14:11:38 MST 2017
^C
I.e., (save-buffers-kill-emacs)
hangs (unlike (server-shutdown)
) at commandline until killed with C-c
. (This appears to be due to a currently-open Emacs bug from 2013, as noted by npostavs.) Furthermore, like (server-shutdown)
above, it does nothing about the daemon process:
me@it: ~ $ date ; pgrep -l emacs
Sun Oct 8 14:12:12 MST 2017
6087 emacs
me@it: ~ $ date ; find ~/.emacs.d/ -name '*lock*'
Sun Oct 8 14:12:37 MST 2017
/home/me/.emacs.d/personal/.emacs.desktop.lock
(save-buffers-kill-emacs)
can be made not to hang (as suggested by Basil), but it still does not work (i.e., gracefully kill the daemon):
me@it:~$ date ; pgrep -l emacs
Mon Oct 9 22:50:39 MST 2017
me@it:~$ date ; find ~/.emacs.d/ -name '*lock*'
Mon Oct 9 22:50:42 MST 2017
me@it:~$ date ; emacs --daemon &
Mon Oct 9 22:51:01 MST 2017
... console spew follows ...
me@it:~$ date ; pgrep -l emacs
Mon Oct 9 22:51:20 MST 2017
8378 emacs
me@it:~$ date ; find ~/.emacs.d/ -name '*lock*'
Mon Oct 9 22:51:26 MST 2017
/home/me/.emacs.d/personal/.emacs.desktop.lock
me@it:~$ date ; emacsclient --eval '(save-buffers-kill-emacs)' --tty
Mon Oct 9 22:51:51 MST 2017
Key y
at the prompt (IIRC, text is This Emacs session has clients; exit anyway?
) and the terminal client exits immediately. But it does not kill the server:
me@it:~$ date ; pgrep -l emacs
Mon Oct 9 22:51:59 MST 2017
8378 emacs
me@it:~$ date ; find ~/.emacs.d/ -name '*lock*'
Mon Oct 9 22:52:05 MST 2017
/home/me/.emacs.d/personal/.emacs.desktop.lock
kill-emacs-hook
might query for input and thus halt the shutdown process.(save-buffers-kill-emacs) and related