2

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

  1. (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 ...
    
  2. (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

  1. cleanup (e.g., delete its desktop lockfile), before ...
  2. 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
  • I once had the same question, but gave up to find a general answer. Any code running from kill-emacs-hook might query for input and thus halt the shutdown process. – politza Oct 8 '17 at 14:06
  • Re hanging, this is an open problem in Emacs, cf Bug#13697. – npostavs Oct 9 '17 at 14:44
  • @npostavs: thanks, now noted in section=(save-buffers-kill-emacs) and related – TomRoche Oct 11 '17 at 2:49
-1

The first function in my ~/.emacs.d/init.el is one I got from here:

(defun server-shutdown () "Save buffers, Quit, and Shutdown (kill) server" (interactive) (save-some-buffers) (kill-emacs))

After that, I can emacsclient -t -e '(server-shutdown)'

  • I believe you can replace your (server-shutdown) with the built-in (save-buffers-kill-emacs). – Basil Oct 8 '17 at 12:13
  • @izkon: see failure described at section=(save-buffers-kill-emacs) and related – TomRoche Oct 8 '17 at 21:54
  • @Basil: see failure described at section=(save-buffers-kill-emacs) and related – TomRoche Oct 8 '17 at 21:55
  • @TomRoche Have you tried combining --tty and --eval '(save-buffers-kill-emacs)'? – Basil Oct 8 '17 at 22:12
  • @Basil: thanks for the tip--not a fix, but one more datapoint. See updated end of section=(save-buffers-kill-emacs) and related – TomRoche Oct 10 '17 at 6:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.