GNU bug report logs -
#51377
Automatically exit server when it has no remaining clients
Previous Next
Reported by: Gregory Heytings <gregory <at> heytings.org>
Date: Sun, 24 Oct 2021 15:16:01 UTC
Severity: wishlist
Tags: patch
Fixed in version 29.1
Done: Lars Ingebrigtsen <larsi <at> gnus.org>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 51377 in the body.
You can then email your comments to 51377 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 15:16:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Gregory Heytings <gregory <at> heytings.org>
:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org
.
(Sun, 24 Oct 2021 15:16:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
As discussed in
https://lists.gnu.org/archive/html/emacs-devel/2021-10/msg01465.html , an
option to stop the Emacs server when it has no clients anymore (which is
similar to what some other apps do, for example browsers) would be useful.
Patch attached.
[Option-to-stop-emacs-server-when-it-has-no-clients-a.patch (text/x-diff, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 16:04:01 GMT)
Full text and
rfc822 format available.
Message #8 received at 51377 <at> debbugs.gnu.org (full text, mbox):
On 10/24/2021 8:15 AM, Gregory Heytings wrote:
>
> As discussed in
> https://lists.gnu.org/archive/html/emacs-devel/2021-10/msg01465.html ,
> an option to stop the Emacs server when it has no clients anymore (which
> is similar to what some other apps do, for example browsers) would be
> useful.
>
> Patch attached.
I'm not sure I understand the patch; `save-buffers-kill-emacs' prompts
the user to save buffers before killing Emacs, but how would that work
in a daemon when there are no frames remaining?
I use a slightly-modified form of the following in my configuration,
which I'm working on hooking up to a flag to remember if the daemon was
started lazily:
--------------------------------------------------
(defun save-buffers-kill-terminal (&optional arg)
"Offer to save each buffer, then kill the current connection.
If the current frame has no client or is the last client of a daemon,
kill Emacs itself using `save-buffers-kill-emacs'.
With prefix ARG, silently save all file-visiting buffers, then kill.
If emacsclient was started with a list of filenames to edit, then
only these files will be asked to be saved."
(interactive "P")
;; Only kill the terminal if the current frame is a client. However, if
;; Emacs was started as a daemon and this is the last client, kill Emacs
;; entirely.
(if-let ((this-client (frame-parameter nil 'client))
((not (and (daemonp)
(equal server-clients (list this-client))))))
(server-save-buffers-kill-terminal arg)
(save-buffers-kill-emacs arg)))
(defun server-kill-emacs-query-function ()
"Ask before exiting Emacs if it has live clients.
If Emacs was started as a daemon and the only live client is the
current frame's client, don't bother asking."
(let ((ignored-client (and (daemonp) (frame-parameter nil 'client))))
(or (not (seq-some (lambda (client)
(unless (eq ignored-client client)
(seq-some #'buffer-live-p
(process-get client 'buffers))))
server-clients))
(yes-or-no-p "This Emacs session has clients; exit anyway? "))))
--------------------------------------------------
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 16:15:01 GMT)
Full text and
rfc822 format available.
Message #11 received at 51377 <at> debbugs.gnu.org (full text, mbox):
On 10/24/2021 9:03 AM, Jim Porter wrote:
> I use a slightly-modified form of the following in my configuration,
> which I'm working on hooking up to a flag to remember if the daemon was
> started lazily:
[snip]
Note: the code I posted doesn't handle `emacsclient -n' (I don't use
that option, so it doesn't come up in my configuration), but it
shouldn't be hard to handle that case once I have a real patch put together.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 16:33:01 GMT)
Full text and
rfc822 format available.
Message #14 received at 51377 <at> debbugs.gnu.org (full text, mbox):
>
> I'm not sure I understand the patch; `save-buffers-kill-emacs' prompts
> the user to save buffers before killing Emacs, but how would that work
> in a daemon when there are no frames remaining?
>
There is one (invisible) frame remaining: the daemon frame. And when
there are no other frames (graphical or non-graphical) ones, there's
nothing to save, save-buffer-kill-emacs just kills emacs. The patch just
checks every two seconds if there are remaining frames (apart from the
daemon one), and if not, it kills emacs. And it works with and without
-n.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 18:10:03 GMT)
Full text and
rfc822 format available.
Message #17 received at 51377 <at> debbugs.gnu.org (full text, mbox):
On 10/24/2021 9:32 AM, Gregory Heytings wrote:
>> I'm not sure I understand the patch; `save-buffers-kill-emacs' prompts
>> the user to save buffers before killing Emacs, but how would that work
>> in a daemon when there are no frames remaining?
>
> There is one (invisible) frame remaining: the daemon frame. And when
> there are no other frames (graphical or non-graphical) ones, there's
> nothing to save, save-buffer-kill-emacs just kills emacs.
I don't think this is true in general. The docstring for
`server-save-buffers-kill-terminal' says: "If emacsclient was started
with a list of filenames to edit, then only these files will be asked to
be saved." As a result, some files with unsaved changes may still exist,
so we'd want to prompt about those *before* the last frame is closed.
To see this in action:
$ emacs -Q --daemon
$ emacsclient foo.txt
C-x C-f bar.txt
;; Make some edits
C-x C-c
;; Exits immediately without prompting about saving bar.txt
If `save-buffers-kill-emacs' were called after that, the Emacs daemon
would be killed, losing the edits to bar.txt.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 18:44:01 GMT)
Full text and
rfc822 format available.
Message #20 received at 51377 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
>
> If `save-buffers-kill-emacs' were called after that, the Emacs daemon
> would be killed, losing the edits to bar.txt.
>
Indeed, you are correct. Updated patch attached, which also takes care of
running processes.
[Option-to-automatically-stop-Emacs-server.patch (text/x-diff, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 19:40:02 GMT)
Full text and
rfc822 format available.
Message #23 received at 51377 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 10/24/2021 11:43 AM, Gregory Heytings wrote:
>>
>> If `save-buffers-kill-emacs' were called after that, the Emacs daemon
>> would be killed, losing the edits to bar.txt.
>
> Indeed, you are correct. Updated patch attached, which also takes care
> of running processes.
Yeah, that looks like it should avoid any data loss. However, it's not
the behavior I'd personally expect. As I understand it, this will just
keep the Emacs daemon alive if there are any unsaved files. I'd find it
easier to use if Emacs warned the user about unsaved files before
killing the last client. Then, Emacs can safely kill the daemon once
I've confirmed that that's what I want.
I've attached a lightly-tested patch series that implements things in
the way that I'd be happiest with. There are a few points I should
explain though.
First, I chose to add a new --lazy-daemon option (I'm not sure about the
name; feel free to suggest a better one). This makes it possible to
distinguish whether the daemon was started on demand via `emacsclient'.
I chose a command-line option rather than a command accepted by the
server protocol because all the other server protocol commands can be
used any time a new `emacsclient' is started; this option only makes
sense when starting the daemon (since it describes how the daemon was
started). I also chose to add this as a "third" daemon type rather than
an entirely separate flag since I don't think there's any reason to
support a lazily-created foreground daemon.
In the second patch, I added a minor performance optimization to
`server-kill-emacs-query-function'. Now it stops once it finds the first
live client. This patch isn't strictly required though, and I could
rework things to exclude it.
Next, I updated `server-save-buffers-kill-terminal' to check if the
server is a lazy daemon and if the current client is the last one: if
so, it calls `save-buffers-kill-emacs', which then calls an improved
`server-kill-emacs-query-function' that knows to avoid prompting
unnecessarily when this is the last client.
Notably, the change to `server-save-buffers-kill-terminal' alters the
behavior of killing a frame created by `emacsclient -n'. Looking at the
code before, I don't see how it could possibly have been the right
behavior: if there were multiple frames open, it only closed *one*
frame, even if all of those frames were created after a single call of
`emacsclient -n' (e.g. by calling `make-frame-command'). If it was the
*last* frame, it killed Emacs, even if the user explicitly called `emacs
--daemon' on system boot and wants the daemon to live forever. I've
changed the behavior so that when you call this from a `nowait' frame,
it kills Emacs if a) it's a lazy daemon and b) there are no other
clients. That's a lot closer to the behavior when calling this from a
"normal" client frame.
Finally, these patches would all require documentation improvements to
merge. However, it didn't seem like a good use of my time to do that
until people agree that this is the right strategy overall.
[0001-Add-lazy-daemon-option-used-to-start-a-daemon-on-dem.patch (text/plain, attachment)]
[0002-Stop-searching-for-live-clients-once-we-find-one.patch (text/plain, attachment)]
[0003-When-killing-the-last-client-attached-to-a-lazy-daem.patch (text/plain, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 20:43:01 GMT)
Full text and
rfc822 format available.
Message #26 received at 51377 <at> debbugs.gnu.org (full text, mbox):
>
> Yeah, that looks like it should avoid any data loss. However, it's not
> the behavior I'd personally expect. As I understand it, this will just
> keep the Emacs daemon alive if there are any unsaved files.
>
Indeed. And if there are any running processes. This is I think the
least surprising behavior for users who use the Emacs daemon.
>
> I'd find it easier to use if Emacs warned the user about unsaved files
> before killing the last client. Then, Emacs can safely kill the daemon
> once I've confirmed that that's what I want.
>
I'm not sure I understand why this would be better.
If want you want is to save unsaved buffers and stop the daemon when you
close the last frame, you can simply use:
(defun save-buffers-kill-terminal (&optional arg)
(interactive "P")
(if (and (frame-parameter nil 'client)
(cddr (frame-list)))
(server-save-buffers-kill-terminal arg)
(save-buffers-kill-emacs arg)))
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 21:20:01 GMT)
Full text and
rfc822 format available.
Message #29 received at 51377 <at> debbugs.gnu.org (full text, mbox):
On 10/24/2021 1:42 PM, Gregory Heytings wrote:
>
>>
>> Yeah, that looks like it should avoid any data loss. However, it's not
>> the behavior I'd personally expect. As I understand it, this will just
>> keep the Emacs daemon alive if there are any unsaved files.
>>
>
> Indeed. And if there are any running processes. This is I think the
> least surprising behavior for users who use the Emacs daemon.
I'd find it quite surprising, since an errant edit to any open file
would prevent the server from exiting after the last client stops. While
leaving the server running isn't the worst thing ever (indeed, that's
how it works now), I'd want the logic for when the server exits to be as
simple as possible, i.e. "when there are no more clients, exit"
(provided the user has confirmed as necessary). Having the server stick
around because I forgot to save one file would surprise me, mainly
because it would typically happen after, well, I forgot something.
>> I'd find it easier to use if Emacs warned the user about unsaved files
>> before killing the last client. Then, Emacs can safely kill the daemon
>> once I've confirmed that that's what I want.
>>
>
> I'm not sure I understand why this would be better.
Coming from a non-daemon configuration, my expectation is that
`save-buffers-kill-terminal' typically kills Emacs entirely. The
behavior I'm looking for is: I can have multiple clients (or
"terminals", as the function calls them) connected to the Emacs daemon,
but once I'm down to just one client, `save-buffers-kill-terminal' works
like it does in a non-daemon/server configuration. Then, in terms of my
use pattern, the extra clients work like an addition on top of the
behavior I'm used to (i.e. running `emacs' directly).
> If want you want is to save unsaved buffers and stop the daemon when you
> close the last frame, you can simply use:
>
> (defun save-buffers-kill-terminal (&optional arg)
> (interactive "P")
> (if (and (frame-parameter nil 'client)
> (cddr (frame-list)))
> (server-save-buffers-kill-terminal arg)
> (save-buffers-kill-emacs arg)))
That's pretty much what I started with, actually. I've added more to
that as I find corner cases, and as I try to make my code work well
under different configurations so that it could merge into Emacs if
there's interest.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 21:38:02 GMT)
Full text and
rfc822 format available.
Message #32 received at 51377 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
>
> I'd find it quite surprising, since an errant edit to any open file
> would prevent the server from exiting after the last client stops. While
> leaving the server running isn't the worst thing ever (indeed, that's
> how it works now), I'd want the logic for when the server exits to be as
> simple as possible, i.e. "when there are no more clients, exit"
> (provided the user has confirmed as necessary). Having the server stick
> around because I forgot to save one file would surprise me, mainly
> because it would typically happen after, well, I forgot something.
>
I see. We have different mental models, I guess. From my viewpoint the
Emacs server should stay there until it's not necessary, and I'd be
surprised to be queried about what to do with buffers opened of processes
started in a frame I already closed when I want to close another frame.
But of course I do not object to have both behaviors.
>
> That's pretty much what I started with, actually. I've added more to
> that as I find corner cases, and as I try to make my code work well
> under different configurations so that it could merge into Emacs if
> there's interest.
>
I attach a patch for that other behavior, it works fine AFAICS.
[Option-to-stop-Emacs-server-when-last-client-exits.patch (text/x-diff, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Sun, 24 Oct 2021 21:41:01 GMT)
Full text and
rfc822 format available.
Message #35 received at 51377 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 10/24/2021 12:39 PM, Jim Porter wrote:
> Next, I updated `server-save-buffers-kill-terminal' to check if the
> server is a lazy daemon and if the current client is the last one: if
> so, it calls `save-buffers-kill-emacs', which then calls an improved
> `server-kill-emacs-query-function' that knows to avoid prompting
> unnecessarily when this is the last client.
I amended the third patch (attached) to account for this change in
`handle-delete-frame'. This ensures that if you delete the last
(non-daemon) frame using this method, it calls `save-buffers-kill-emacs'
to ask the relevant questions.
[0003-When-killing-the-last-client-attached-to-a-lazy-daem.patch (text/plain, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Mon, 25 Oct 2021 18:23:03 GMT)
Full text and
rfc822 format available.
Message #38 received at 51377 <at> debbugs.gnu.org (full text, mbox):
On 10/24/2021 2:37 PM, Gregory Heytings wrote:
> I see. We have different mental models, I guess. From my viewpoint the
> Emacs server should stay there until it's not necessary, and I'd be
> surprised to be queried about what to do with buffers opened of
> processes started in a frame I already closed when I want to close
> another frame. But of course I do not object to have both behaviors.
[snip]
>
> I attach a patch for that other behavior, it works fine AFAICS.
There are a few issues that I found when doing this previously:
1) I think it should check whether there are other *clients*, not other
*frames*. One client might have multiple frames open, and `C-x C-c'
closes all frames for the current client. If there's only one client
left, but it has two frames open, it should still kill the server, since
there will be no more (non-daemon) frames after `C-x C-c'. (Also, it
should check `(daemonp)', since this logic doesn't apply to a client of
a non-daemon Emacs.)
2) When killing the Emacs daemon from the last client,
`server-kill-emacs-query-function' (probably) doesn't need to warn you
that there are still clients. There's only the one client remaining,
which the user already intends to kill (albeit indirectly, by killing
the daemon).
3) `handle-delete-frame' (used when clicking the X button in your window
manager) can also call `save-buffers-kill-emacs' if the user closed the
last frame. The logic here should exclude the daemon frame from counting
as another frame so that closing all frames via the window manager stops
the daemon too.
I did the above in my patch[1], which could be modified pretty easily to
use the `server-stop-when-closing-last-frame' option you added in your
patch. There might be other cases I haven't accounted for, but it's
working so far in my local configuration.
[1] https://lists.gnu.org/archive/html/bug-gnu-emacs/2021-10/msg02209.html
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Tue, 26 Oct 2021 10:38:02 GMT)
Full text and
rfc822 format available.
Message #41 received at 51377 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
>
> 1) I think it should check whether there are other *clients*, not other
> *frames*.
>
No, because nowait client frames are not recorded as clients. There's no
way around it, it's necessary to use frames.
>
> 3) `handle-delete-frame' (used when clicking the X button in your window
> manager) can also call `save-buffers-kill-emacs' if the user closed the
> last frame. The logic here should exclude the daemon frame from counting
> as another frame so that closing all frames via the window manager stops
> the daemon too.
>
If it's now also necessary to kill the daemon when you close the last
Emacs frame with the window manager close button (I did not see this
requirement in your original post), then it's also necessary to kill the
daemon when you close the last Emacs frame with C-x 5 0 (delete-frame),
because it's what Emacs tells you to do when you call emacsclient without
a file argument.
Here's a combined patch, which implements the two desired behaviors, and
which I believe handles all cases properly: delete-frame,
handele-delete-frame, save-buffers-kill-terminal, wait and nowait clients.
[Options-to-automatically-stop-the-Emacs-server.patch (text/x-diff, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Tue, 26 Oct 2021 12:00:03 GMT)
Full text and
rfc822 format available.
Message #44 received at 51377 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
>
> Here's a combined patch, which implements the two desired behaviors, and
> which I believe handles all cases properly: delete-frame,
> handele-delete-frame, save-buffers-kill-terminal, wait and nowait
> clients.
>
It just occurred to me that it's very easy to add a third behavior, namely
the one you expect, but only when the last frame is killed with C-x C-c.
See attached patch.
[Options-to-automatically-stop-the-Emacs-server.patch (text/x-diff, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Tue, 26 Oct 2021 15:08:02 GMT)
Full text and
rfc822 format available.
Message #47 received at 51377 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
And here is a slightly improved version of the patch, with a NEWS entry.
[Options-to-automatically-stop-the-Emacs-server.patch (text/x-diff, attachment)]
Added tag(s) patch.
Request was from
Stefan Kangas <stefan <at> marxist.se>
to
control <at> debbugs.gnu.org
.
(Thu, 28 Oct 2021 03:23:04 GMT)
Full text and
rfc822 format available.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#51377
; Package
emacs
.
(Thu, 11 Nov 2021 05:44:01 GMT)
Full text and
rfc822 format available.
Message #52 received at 51377 <at> debbugs.gnu.org (full text, mbox):
Gregory Heytings <gregory <at> heytings.org> writes:
> And here is a slightly improved version of the patch, with a NEWS entry.
Makes sense to me; pushed to Emacs 29 now (with some tiny changes).
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog: http://lars.ingebrigtsen.no
bug marked as fixed in version 29.1, send any further explanations to
51377 <at> debbugs.gnu.org and Gregory Heytings <gregory <at> heytings.org>
Request was from
Lars Ingebrigtsen <larsi <at> gnus.org>
to
control <at> debbugs.gnu.org
.
(Thu, 11 Nov 2021 05:44:02 GMT)
Full text and
rfc822 format available.
bug archived.
Request was from
Debbugs Internal Request <help-debbugs <at> gnu.org>
to
internal_control <at> debbugs.gnu.org
.
(Thu, 09 Dec 2021 12:24:08 GMT)
Full text and
rfc822 format available.
This bug report was last modified 2 years and 131 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.