From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: Paul Pogonyshev Newsgroups: gmane.emacs.devel Subject: Re: graceful shutdown of non-interactive Elisp program Date: Sun, 14 Jun 2020 18:47:26 +0200 Message-ID: References: <83imft3d55.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="0000000000005bb8b705a80e1119" Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="23588"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Emacs developers To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun Jun 14 18:48:39 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jkVoE-00062T-Fg for ged-emacs-devel@m.gmane-mx.org; Sun, 14 Jun 2020 18:48:38 +0200 Original-Received: from localhost ([::1]:48586 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jkVoD-000562-Hi for ged-emacs-devel@m.gmane-mx.org; Sun, 14 Jun 2020 12:48:37 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:58008) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jkVnT-0004Io-Qo for emacs-devel@gnu.org; Sun, 14 Jun 2020 12:47:51 -0400 Original-Received: from mail-wr1-x42d.google.com ([2a00:1450:4864:20::42d]:37544) by eggs.gnu.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jkVnR-00014O-Sk; Sun, 14 Jun 2020 12:47:51 -0400 Original-Received: by mail-wr1-x42d.google.com with SMTP id x13so14688470wrv.4; Sun, 14 Jun 2020 09:47:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=TjaWzK1Ahbe23i99x7hCzsS4tZGQwZ4a7FUs2LtiQwo=; b=TKKXPJMNGkQkFM/LPlhLbrfSJ1DhRULrbENWcT0lCLMmdRYef+uyB2W+HoPRsZjMxS rJgd7yq7ZjMQGb/BfQldkuFsXqaCTkel+7QNSy5PJ3dl/oYMLqPSrdzYd4jKkoe3vOvk rO92pQnleAdkcXbc18po0idOt4Zm/nHc3xx3/2jRMrN5BL484RQ4nbg4EfJVGYVLwBeR hy/fX8AH+8aL/axqudL9/7r5yt5BQhlo2A+lL5JclfHnOj2kNidomS0BL4W8sXbmFmFJ 2lBis4FiTlvKjHHVV24fg1fEBL8cTJVBaNBOkW0Jod3g7+Jom7MvMLqRAGPz6zy/E5yf 7IjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=TjaWzK1Ahbe23i99x7hCzsS4tZGQwZ4a7FUs2LtiQwo=; b=eM1R4SG6IpLQFqEidzixW9MuOHWe5BamRT0JkcPWYB6U4QhZmNj7rhHm5fCDf5VdAv qBGm8Dyz1CdvjceIiGCwDVEWHOLO/8fAxQhQzlqVszv64UB/iZkwKsKxTK+YozD6mhHL EwKlIFdBUQoMMl+F32wxmw5jFO/vJelC2NxQKAyj6zkmHFRx2pA1ji1BWFFDtK/SqkQq /427GgddcCaUAl1Wbt/Nu+NEibGqJ20THjsS3jml0XKTo9YH1qwoPT8OMfl7iDAqwdty NzgJbExkESP+5eH5Am6FFp+gQNS3oJPCxURYeVfjPIX+3E/24OqU3OJx8L4AGOp/edDr fVGw== X-Gm-Message-State: AOAM532RnZAQSbYoLdkAzrPlW4hhCuAietgvPIKjGWzbDcCCiS5QZ2fG Gh5yGV4Ls1O+vRJx1KcgNcY27CsIcwmB0SKctBxHrJU= X-Google-Smtp-Source: ABdhPJzlQyQSC4LW0ndPYfzAS8clEWyueCN/l5eR//4HdETQvUrNXYP63NPBGNlevHIrlnqVSbYuWDHz5WUQ0tpy9H0= X-Received: by 2002:a5d:42cd:: with SMTP id t13mr24251752wrr.355.1592153257784; Sun, 14 Jun 2020 09:47:37 -0700 (PDT) In-Reply-To: <83imft3d55.fsf@gnu.org> Received-SPF: pass client-ip=2a00:1450:4864:20::42d; envelope-from=pogonyshev@gmail.com; helo=mail-wr1-x42d.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:252236 Archived-At: --0000000000005bb8b705a80e1119 Content-Type: text/plain; charset="UTF-8" > 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. > --0000000000005bb8b705a80e1119 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
> 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 fr= om passing an
exception from a `kill-emacs-hook' to the "= ;main" code:

$ emacs --batch \
=C2=A0 =C2=A0 =C2=A0 =C2=A0 --eval "(add-hook 'kill-ema= cs-hook (lambda () (signal 'unwind-the-stack nil)))" \
=C2=A0 =C2=A0 =C2=A0 =C2=A0 --eval "(unwind-protect (while t) (mes= sage \"GOING DOWN\"))"

^CError in kill-emacs-hook ((closure (t) nil (signal 'unwind-the-st= ack nil))): (unwind-the-stack)

As you s= ee, the exception doesn't succeed in making `unwind-protect'
<= div>clause to run.

> And if you had a say i= n 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
al= locations 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

=C2=A0 =C2=A0(unwind-protect
=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0(do-something-with-resource-N)
=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0(free) (resource-N) (code))

twenty times. However, as i= t stands it looks that I have to do

=C2=A0=C2=A0=C2=A0(let ((free-resource-N (lambda () (free= ) (resource-N) (code))))
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(add-hook 'k= ill-emacs-hook free-resource-N)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(unwind-p= rotect
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(do-someth= ing-with-resource-N)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(funcall= free-resource-N))
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(remove-hook 'kill= -emacs-hook free-resource-N))

every time.

Additionally,= this won't work if I don't control the code that
allocat= es/frees the resource, i.e. if it happens to be inside some
exter= nal package.

> Also, you mention batch mode, bu= t is it relevant?

No, not really. It's just th= at in batch mode I was expecting to be in full
control of Emacs &= quot;command loop" because I don't share Emacs with any
= other code (or at most that code can be seen as a "library" for m= y
program). In interactive mode it's basically the same.

Paul


On Sun, 14 Jun 2020 at 17:01,= Eli Zaretskii <eliz@gnu.org> wro= te:
> From: P= aul 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-interactiv= e mode, i.e. essentially as `emacs --batch
> --load myfile.el'. A normal way to shutdown terminal programs is w= ith 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 co= nstantly 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:
>
>=C2=A0 =C2=A0 =C2=A0$ 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). Ho= wever, 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.=C2=A0 If you want to raise an exception from a<= br> 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?=C2=A0 That is, are you saying that Emacs behaves differently in an interactive session when
it gets a fatal signal?

I'm confused.
--0000000000005bb8b705a80e1119--