* unwind-protect within while-no-input
@ 2024-05-03 12:45 Spencer Baugh
2024-05-07 18:05 ` Spencer Baugh
0 siblings, 1 reply; 47+ messages in thread
From: Spencer Baugh @ 2024-05-03 12:45 UTC (permalink / raw)
To: emacs-devel
I have some process which takes input on stdin; if I don't finish
sending the input on stdin for any reason, the process will sit around
forever waiting. I'd like to delete the process rather than letting it
linger in that case.
My code (simplified somewhat) looks like:
(defun make-my-proc ()
(let (proc finished-sending)
(unwind-protect
(progn
(setq proc (make-process :command '("cat")))
(process-send-string proc "some large string")
(process-send-eof proc)
(setq finished-sending t)
proc)
(unless finished-sending
(delete-process proc)))))
However, this seems to be incorrect. When this is called within a
(while-no-input (make-my-proc)) I sometimes get lingering processes
which haven't received their full input.
Is this because while-no-input can cause a signal to be thrown in the
unwind-forms before the delete-process call?
If so, how can I robustly delete the process?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-03 12:45 unwind-protect within while-no-input Spencer Baugh
@ 2024-05-07 18:05 ` Spencer Baugh
2024-05-07 18:49 ` Eli Zaretskii
2024-05-26 2:47 ` Stefan Monnier via Emacs development discussions.
0 siblings, 2 replies; 47+ messages in thread
From: Spencer Baugh @ 2024-05-07 18:05 UTC (permalink / raw)
To: emacs-devel
Put another way:
It seems like it's impossible right now to use unwind-protect robustly
in face of quits, because a quit triggered in the body forms of the
unwind-protect will also interrupt the unwind forms.
And there is no way to work around this, because binding inhibit-quit
in the unwind forms can *also* be interrupted.
Maybe there should be a version of unwind-protect which automatically
and atomically inhibits quit in the unwind forms?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-07 18:05 ` Spencer Baugh
@ 2024-05-07 18:49 ` Eli Zaretskii
2024-05-07 19:43 ` Spencer Baugh
2024-05-26 2:47 ` Stefan Monnier via Emacs development discussions.
1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2024-05-07 18:49 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Tue, 07 May 2024 14:05:54 -0400
>
> It seems like it's impossible right now to use unwind-protect robustly
> in face of quits, because a quit triggered in the body forms of the
> unwind-protect will also interrupt the unwind forms.
I think you can use condition-case for that:
(setq foo
(condition-case nil
(while t nil)
(quit 'interrupted))) C-M-x C-g
=> interrupted
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-07 18:49 ` Eli Zaretskii
@ 2024-05-07 19:43 ` Spencer Baugh
2024-05-08 3:59 ` Po Lu
2024-05-08 11:52 ` Eli Zaretskii
0 siblings, 2 replies; 47+ messages in thread
From: Spencer Baugh @ 2024-05-07 19:43 UTC (permalink / raw)
To: emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> It seems like it's impossible right now to use unwind-protect robustly
>> in face of quits, because a quit triggered in the body forms of the
>> unwind-protect will also interrupt the unwind forms.
>
> I think you can use condition-case for that:
>
> (setq foo
> (condition-case nil
> (while t nil)
> (quit 'interrupted))) C-M-x C-g
> => interrupted
That doesn't work with while-no-input:
(let (foo)
(while-no-input
(condition-case nil
(while t nil)
(quit (setq foo 'interrupted))))
foo) C-x C-e aaa
=> nil
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-07 19:43 ` Spencer Baugh
@ 2024-05-08 3:59 ` Po Lu
2024-05-08 11:42 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 11:52 ` Eli Zaretskii
1 sibling, 1 reply; 47+ messages in thread
From: Po Lu @ 2024-05-08 3:59 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
Spencer Baugh <sbaugh@janestreet.com> writes:
> That doesn't work with while-no-input:
>
> (let (foo)
> (while-no-input
> (condition-case nil
> (while t nil)
> (quit (setq foo 'interrupted))))
> foo) C-x C-e aaa
(let (foo)
(while-no-input
(let ((inhibit-quit t))
(unwind-protect
(let ((inhibit-quit nil))
(while t nil))
(setq foo 'interrupted))))
foo)
? Just a stab in the dark, I'm afraid.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 3:59 ` Po Lu
@ 2024-05-08 11:42 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 11:47 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 12:12 ` Eli Zaretskii
0 siblings, 2 replies; 47+ messages in thread
From: Michael Heerdegen via Emacs development discussions. @ 2024-05-08 11:42 UTC (permalink / raw)
To: emacs-devel
Po Lu <luangruo@yahoo.com> writes:
> ? Just a stab in the dark, I'm afraid.
`unwind-protect' works as expected:
#+begin_src emacs-lisp
(let (foo)
(while-no-input
(unwind-protect (while t nil)
(setq foo 'interrupted)))
(message "foo: %s" foo))
#+end_src
Michael.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 11:42 ` Michael Heerdegen via Emacs development discussions.
@ 2024-05-08 11:47 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 13:44 ` Spencer Baugh
2024-05-08 12:12 ` Eli Zaretskii
1 sibling, 1 reply; 47+ messages in thread
From: Michael Heerdegen via Emacs development discussions. @ 2024-05-08 11:47 UTC (permalink / raw)
To: emacs-devel
Michael Heerdegen via "Emacs development discussions."
<emacs-devel@gnu.org> writes:
> `unwind-protect' works as expected:
>
> #+begin_src emacs-lisp
> (let (foo)
> (while-no-input
> (unwind-protect (while t nil)
> (setq foo 'interrupted)))
> (message "foo: %s" foo))
> #+end_src
Note the unwind forms are executed even if you quit:
#+begin_src emacs-lisp
(let (foo)
(while-no-input
(unwind-protect (while t nil)
(setq foo 'interrupted)
(message "foo: %s" foo)))
(message "foo: %s" foo))
#+end_src
Am I'm missing something?
Michael.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-07 19:43 ` Spencer Baugh
2024-05-08 3:59 ` Po Lu
@ 2024-05-08 11:52 ` Eli Zaretskii
2024-05-08 13:57 ` Spencer Baugh
1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2024-05-08 11:52 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Tue, 07 May 2024 15:43:43 -0400
>
> Eli Zaretskii <eliz@gnu.org> writes:
> >> It seems like it's impossible right now to use unwind-protect robustly
> >> in face of quits, because a quit triggered in the body forms of the
> >> unwind-protect will also interrupt the unwind forms.
> >
> > I think you can use condition-case for that:
> >
> > (setq foo
> > (condition-case nil
> > (while t nil)
> > (quit 'interrupted))) C-M-x C-g
> > => interrupted
>
> That doesn't work with while-no-input:
The message to which I responded said nothing about while-no-input, it
made a much more general and broad assertion, see above.
But if while-no-input must be in the picture, then you just need to do
it the other way around:
(progn
(setq foo
(condition-case nil
(let ((i 0))
(while-no-input
(while (< i 100000000)
(setq i (1+ i)))
i))
(quit 'interrupted)))
foo)
This produces:
* The last i value in the loop if run uninterrupted
* ‘interrupted’ if interrupted by C-g (QUIT)
* t if interrupted by input
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 11:42 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 11:47 ` Michael Heerdegen via Emacs development discussions.
@ 2024-05-08 12:12 ` Eli Zaretskii
2024-05-08 12:36 ` Michael Heerdegen via Emacs development discussions.
1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2024-05-08 12:12 UTC (permalink / raw)
To: Michael Heerdegen; +Cc: emacs-devel
> Date: Wed, 08 May 2024 13:42:50 +0200
> From: Michael Heerdegen via "Emacs development discussions." <emacs-devel@gnu.org>
>
> Po Lu <luangruo@yahoo.com> writes:
>
> > ? Just a stab in the dark, I'm afraid.
>
> `unwind-protect' works as expected:
>
> #+begin_src emacs-lisp
> (let (foo)
> (while-no-input
> (unwind-protect (while t nil)
> (setq foo 'interrupted)))
> (message "foo: %s" foo))
> #+end_src
It does, indeed, work, but it doesn't discern between C-g and any
other input.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 12:12 ` Eli Zaretskii
@ 2024-05-08 12:36 ` Michael Heerdegen via Emacs development discussions.
0 siblings, 0 replies; 47+ messages in thread
From: Michael Heerdegen via Emacs development discussions. @ 2024-05-08 12:36 UTC (permalink / raw)
To: emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
> It does, indeed, work, but it doesn't discern between C-g and any
> other input.
Sure sure... but I'm thinking about the original question, where that
had not been demanded.
I have been trying this:
(let (proc finished-sending)
(unwind-protect
(progn
(setq proc (make-process :command '("cat") :name "testprocess"))
(process-send-string proc "some large string")
(process-send-eof proc)
(setq finished-sending t)
proc)
(unless finished-sending
(delete-process proc))))
This leaves me with running processes although the unwind forms have
been executed - just because `finished-sending' is non-nil.
So maybe the problem is something completely different? Just asking...
Michael.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 11:47 ` Michael Heerdegen via Emacs development discussions.
@ 2024-05-08 13:44 ` Spencer Baugh
2024-05-08 16:13 ` Michael Heerdegen via Emacs development discussions.
0 siblings, 1 reply; 47+ messages in thread
From: Spencer Baugh @ 2024-05-08 13:44 UTC (permalink / raw)
To: emacs-devel
Michael Heerdegen via "Emacs development discussions."
<emacs-devel@gnu.org> writes:
> Michael Heerdegen via "Emacs development discussions."
> <emacs-devel@gnu.org> writes:
>
>> `unwind-protect' works as expected:
>>
>> #+begin_src emacs-lisp
>> (let (foo)
>> (while-no-input
>> (unwind-protect (while t nil)
>> (setq foo 'interrupted)))
>> (message "foo: %s" foo))
>> #+end_src
>
> Note the unwind forms are executed even if you quit:
>
> #+begin_src emacs-lisp
> (let (foo)
> (while-no-input
> (unwind-protect (while t nil)
> (setq foo 'interrupted)
> (message "foo: %s" foo)))
> (message "foo: %s" foo))
> #+end_src
>
> Am I'm missing something?
>
> Michael.
Yes: it doesn't actually work. Try this:
(let (foo)
(while-no-input
(unwind-protect (while t nil)
(sleep-for 10)
(setq foo 'interrupted)
(message "foo: %s" foo)))
(message "foo: %s" foo))
C-x C-e aaaa
Output:
foo: nil
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 11:52 ` Eli Zaretskii
@ 2024-05-08 13:57 ` Spencer Baugh
2024-05-08 14:18 ` Eli Zaretskii
0 siblings, 1 reply; 47+ messages in thread
From: Spencer Baugh @ 2024-05-08 13:57 UTC (permalink / raw)
To: emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Spencer Baugh <sbaugh@janestreet.com>
>> Date: Tue, 07 May 2024 15:43:43 -0400
>>
>> Eli Zaretskii <eliz@gnu.org> writes:
>> >> It seems like it's impossible right now to use unwind-protect robustly
>> >> in face of quits, because a quit triggered in the body forms of the
>> >> unwind-protect will also interrupt the unwind forms.
>> >
>> > I think you can use condition-case for that:
>> >
>> > (setq foo
>> > (condition-case nil
>> > (while t nil)
>> > (quit 'interrupted))) C-M-x C-g
>> > => interrupted
>>
>> That doesn't work with while-no-input:
>
> The message to which I responded said nothing about while-no-input, it
> made a much more general and broad assertion, see above.
1. The unwind forms should run if there is a quit, no matter what
triggered the quit.
2. One thing that might trigger a quit is a while-no-input form outside
my code.
3. Therefore, the unwind forms should be run even when while-no-input
triggers the quit.
Your code does not run the unwind forms when run inside a
while-no-input.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 13:57 ` Spencer Baugh
@ 2024-05-08 14:18 ` Eli Zaretskii
2024-05-08 14:38 ` Spencer Baugh
0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2024-05-08 14:18 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Wed, 08 May 2024 09:57:44 -0400
>
> 1. The unwind forms should run if there is a quit, no matter what
> triggered the quit.
>
> 2. One thing that might trigger a quit is a while-no-input form outside
> my code.
>
> 3. Therefore, the unwind forms should be run even when while-no-input
> triggers the quit.
You keep changing the conditions with each solution that people
propose. What is the purpose of this "salami-like" way of discussing
an issue? Why not state the conditions for the solution you seek
once, and state them completely, and then let people waste less time
on trying to help you?
> Your code does not run the unwind forms when run inside a
> while-no-input.
Why should it? When while-no-input is interrupted by input, it
conceptually is not "quitting"; the fact that it uses quit-flag is an
internal implementation detail.
If you want the unwind forms to run when while-no-input is interrupted
by input, simply do it: while-no-input provides a clear documented
indication that it was interrupted by input, and you can use that to
decide whether to run the unwind forms in that case.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 14:18 ` Eli Zaretskii
@ 2024-05-08 14:38 ` Spencer Baugh
2024-05-08 15:06 ` Eli Zaretskii
2024-05-08 16:17 ` Michael Heerdegen via Emacs development discussions.
0 siblings, 2 replies; 47+ messages in thread
From: Spencer Baugh @ 2024-05-08 14:38 UTC (permalink / raw)
To: emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Spencer Baugh <sbaugh@janestreet.com>
>> Date: Wed, 08 May 2024 09:57:44 -0400
>>
>> 1. The unwind forms should run if there is a quit, no matter what
>> triggered the quit.
>>
>> 2. One thing that might trigger a quit is a while-no-input form outside
>> my code.
>>
>> 3. Therefore, the unwind forms should be run even when while-no-input
>> triggers the quit.
>
> You keep changing the conditions with each solution that people
> propose. What is the purpose of this "salami-like" way of discussing
> an issue? Why not state the conditions for the solution you seek
> once, and state them completely, and then let people waste less time
> on trying to help you?
Sorry, it's not intentional - from my perspective I've been asking for
the same thing each time, with all the same details. But clearly I have
been not fully communicating what I mean.
>> Your code does not run the unwind forms when run inside a
>> while-no-input.
>
> Why should it? When while-no-input is interrupted by input, it
> conceptually is not "quitting"; the fact that it uses quit-flag is an
> internal implementation detail.
Because there might be something I want to clean up.
For example, my code might create a process or temporary directory which
should be deleted even if interrupted by input.
> If you want the unwind forms to run when while-no-input is interrupted
> by input, simply do it: while-no-input provides a clear documented
> indication that it was interrupted by input, and you can use that to
> decide whether to run the unwind forms in that case.
What concretely are you suggesting? Could you give an example in code?
Note that my code doesn't require while-no-input or always run inside
while-no-input - it's just that whenever my code happens to be inside a
while-no-input, my code should still do the cleanup.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 14:38 ` Spencer Baugh
@ 2024-05-08 15:06 ` Eli Zaretskii
2024-05-08 15:14 ` Spencer Baugh
2024-05-08 16:17 ` Michael Heerdegen via Emacs development discussions.
1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2024-05-08 15:06 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Wed, 08 May 2024 10:38:11 -0400
>
> Eli Zaretskii <eliz@gnu.org> writes:
>
> >> Your code does not run the unwind forms when run inside a
> >> while-no-input.
> >
> > Why should it? When while-no-input is interrupted by input, it
> > conceptually is not "quitting"; the fact that it uses quit-flag is an
> > internal implementation detail.
>
> Because there might be something I want to clean up.
>
> For example, my code might create a process or temporary directory which
> should be deleted even if interrupted by input.
>
> > If you want the unwind forms to run when while-no-input is interrupted
> > by input, simply do it: while-no-input provides a clear documented
> > indication that it was interrupted by input, and you can use that to
> > decide whether to run the unwind forms in that case.
>
> What concretely are you suggesting? Could you give an example in code?
I cannot give a concrete example, because even now you describe more
and more details of your code that you haven't disclosed previously.
So any code I will show will most probably not work for you because of
those undisclosed details.
I can only say what I mean generally: the unwind forms are just code,
so when you detect that while-no-input was interrupted by some input,
simply call those unwind forms "by hand". What exactly that means and
how exactly to do that is something the depends on those details and
on what exactly your unwind forms need to do.
> Note that my code doesn't require while-no-input or always run inside
> while-no-input - it's just that whenever my code happens to be inside a
> while-no-input, my code should still do the cleanup.
As I said, while-no-input provides an indication whether it was
interrupted, so you can easily do whatever you need to do in that
case.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 15:06 ` Eli Zaretskii
@ 2024-05-08 15:14 ` Spencer Baugh
2024-05-08 18:51 ` Eli Zaretskii
0 siblings, 1 reply; 47+ messages in thread
From: Spencer Baugh @ 2024-05-08 15:14 UTC (permalink / raw)
To: emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Spencer Baugh <sbaugh@janestreet.com>
>> Date: Wed, 08 May 2024 10:38:11 -0400
>>
>> Eli Zaretskii <eliz@gnu.org> writes:
>>
>> >> Your code does not run the unwind forms when run inside a
>> >> while-no-input.
>> >
>> > Why should it? When while-no-input is interrupted by input, it
>> > conceptually is not "quitting"; the fact that it uses quit-flag is an
>> > internal implementation detail.
>>
>> Because there might be something I want to clean up.
>>
>> For example, my code might create a process or temporary directory which
>> should be deleted even if interrupted by input.
>>
>> > If you want the unwind forms to run when while-no-input is interrupted
>> > by input, simply do it: while-no-input provides a clear documented
>> > indication that it was interrupted by input, and you can use that to
>> > decide whether to run the unwind forms in that case.
>>
>> What concretely are you suggesting? Could you give an example in code?
>
> I cannot give a concrete example, because even now you describe more
> and more details of your code that you haven't disclosed previously.
> So any code I will show will most probably not work for you because of
> those undisclosed details.
>
> I can only say what I mean generally: the unwind forms are just code,
> so when you detect that while-no-input was interrupted by some input,
> simply call those unwind forms "by hand". What exactly that means and
> how exactly to do that is something the depends on those details and
> on what exactly your unwind forms need to do.
>
>> Note that my code doesn't require while-no-input or always run inside
>> while-no-input - it's just that whenever my code happens to be inside a
>> while-no-input, my code should still do the cleanup.
>
> As I said, while-no-input provides an indication whether it was
> interrupted, so you can easily do whatever you need to do in that
> case.
If I have a function:
(defun my-function ()
...do something...)
which might be invoked by some other package that I don't control like this:
(defun some-other-package ()
(while-no-input
...
(my-function)
...))
How does my-function run the unwind-forms when it is interrupted by
while-no-input?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 13:44 ` Spencer Baugh
@ 2024-05-08 16:13 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 17:18 ` Spencer Baugh
0 siblings, 1 reply; 47+ messages in thread
From: Michael Heerdegen via Emacs development discussions. @ 2024-05-08 16:13 UTC (permalink / raw)
To: emacs-devel
Spencer Baugh <sbaugh@janestreet.com> writes:
> Yes: it doesn't actually work. Try this:
>
> (let (foo)
> (while-no-input
> (unwind-protect (while t nil)
> (sleep-for 10)
> (setq foo 'interrupted)
> (message "foo: %s" foo)))
> (message "foo: %s" foo))
>
> C-x C-e aaaa
The intended semantics of `while-no-input' is "terminate the contained
form when there is input".
If there is something in that form that should not been terminated, move
`while-no-input' inwards:
#+begin_src emacs-lisp
(let (foo)
(while-no-input (while t nil))
(sleep-for 10)
(setq foo 'interrupted)
(message "foo: %s" foo)
(message "foo: %s" foo))
#+end_src
or protect the unwind forms against the raised quit:
#+begin_src emacs-lisp
(let (foo)
(while-no-input
(unwind-protect (while t nil)
(let ((inhibit-quit t))
(sleep-for 10)
(setq foo 'interrupted)
(message "foo: %s" foo)))
(message "foo: %s" foo)))
#+end_src
(unwind forms are not per se protected from nonlocal exiting - see
documentation)
depending on what you actually want/need.
Michael.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 14:38 ` Spencer Baugh
2024-05-08 15:06 ` Eli Zaretskii
@ 2024-05-08 16:17 ` Michael Heerdegen via Emacs development discussions.
1 sibling, 0 replies; 47+ messages in thread
From: Michael Heerdegen via Emacs development discussions. @ 2024-05-08 16:17 UTC (permalink / raw)
To: emacs-devel
Spencer Baugh <sbaugh@janestreet.com> writes:
> Sorry, it's not intentional - from my perspective I've been asking for
> the same thing each time, with all the same details. But clearly I have
> been not fully communicating what I mean.
You make us guessing what "it" in "it doesn't work" or "it actually
doesn't work" is.
When it is not clear to you what you actually want, describe the problem
you want to solve and ask for help to solve it.
What we all dislike are questions of the form "I wrote this code, it
doesn't work". As you see, it costs a lot of time to get to the core.
Time that can not be invested into solving other problems.
Michael.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 16:13 ` Michael Heerdegen via Emacs development discussions.
@ 2024-05-08 17:18 ` Spencer Baugh
2024-05-08 20:43 ` Michael Heerdegen via Emacs development discussions.
0 siblings, 1 reply; 47+ messages in thread
From: Spencer Baugh @ 2024-05-08 17:18 UTC (permalink / raw)
To: emacs-devel
Michael Heerdegen via "Emacs development discussions."
<emacs-devel@gnu.org> writes:
> or protect the unwind forms against the raised quit:
>
> #+begin_src emacs-lisp
> (let (foo)
> (while-no-input
> (unwind-protect (while t nil)
> (let ((inhibit-quit t))
> (sleep-for 10)
> (setq foo 'interrupted)
> (message "foo: %s" foo)))
> (message "foo: %s" foo)))
> #+end_src
>
> (unwind forms are not per se protected from nonlocal exiting - see
> documentation)
That seems to work, but is it robust?
If while-no-input can raise a quit between the start of executing
unwindforms and the binding of inhibit-quit, then the unwind forms will
not execute.
Can while-no-input/throw-on-input actually raise a quit then? And is
this behavior documented anywhere?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 15:14 ` Spencer Baugh
@ 2024-05-08 18:51 ` Eli Zaretskii
2024-05-08 19:28 ` Spencer Baugh
2024-05-08 20:34 ` Michael Heerdegen via Emacs development discussions.
0 siblings, 2 replies; 47+ messages in thread
From: Eli Zaretskii @ 2024-05-08 18:51 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Wed, 08 May 2024 11:14:05 -0400
>
> If I have a function:
>
> (defun my-function ()
> ...do something...)
>
> which might be invoked by some other package that I don't control like this:
>
> (defun some-other-package ()
> (while-no-input
> ...
> (my-function)
> ...))
>
> How does my-function run the unwind-forms when it is interrupted by
> while-no-input?
How can a function cause its caller to do anything at all? It can't.
If the caller wants to make sure some unwind-forms will always run
after my-function either returns locally or exits non-locally, the
caller needs to arrange for that.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 18:51 ` Eli Zaretskii
@ 2024-05-08 19:28 ` Spencer Baugh
2024-05-09 5:46 ` Eli Zaretskii
2024-05-08 20:34 ` Michael Heerdegen via Emacs development discussions.
1 sibling, 1 reply; 47+ messages in thread
From: Spencer Baugh @ 2024-05-08 19:28 UTC (permalink / raw)
To: emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Spencer Baugh <sbaugh@janestreet.com>
>> Date: Wed, 08 May 2024 11:14:05 -0400
>>
>> If I have a function:
>>
>> (defun my-function ()
>> ...do something...)
>>
>> which might be invoked by some other package that I don't control like this:
>>
>> (defun some-other-package ()
>> (while-no-input
>> ...
>> (my-function)
>> ...))
>>
>> How does my-function run the unwind-forms when it is interrupted by
>> while-no-input?
>
> How can a function cause its caller to do anything at all? It can't.
> If the caller wants to make sure some unwind-forms will always run
> after my-function either returns locally or exits non-locally, the
> caller needs to arrange for that.
I don't want to run the unwind forms "after" my-function returns or
exits. I want them to run wherever they are inside my-function, just
like a normal unwind-protect.
Let me try to explain again what I want: I want a completely normal
unwind-protect, exactly how unwind-protect works normally:
(unwind-protect BODYFORM UNWINDFORMS...)
Do BODYFORM, protecting with UNWINDFORMS.
If BODYFORM completes normally, its value is returned
after executing the UNWINDFORMS.
If BODYFORM exits nonlocally, the UNWINDFORMS are executed anyway.
Except that I want the UNWINDFORMS to not be interrupted by a
*surrounding* while-no-input or quit or any other kind of nonlocal exit.
Is there any way to do that? ("Move the while-no-input inside the
unwind-protect" is not an answer, because then it's not a *surrounding*
while-no-input anymore)
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 18:51 ` Eli Zaretskii
2024-05-08 19:28 ` Spencer Baugh
@ 2024-05-08 20:34 ` Michael Heerdegen via Emacs development discussions.
1 sibling, 0 replies; 47+ messages in thread
From: Michael Heerdegen via Emacs development discussions. @ 2024-05-08 20:34 UTC (permalink / raw)
To: emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
> > If I have a function:
> >
> > (defun my-function ()
> > ...do something...)
> >
> > which might be invoked by some other package that I don't control
> > like this:
> >
> > (defun some-other-package ()
> > (while-no-input
> > ...
> > (my-function)
> > ...))
> >
> > How does my-function run the unwind-forms when it is interrupted by
> > while-no-input?
>
> How can a function cause its caller to do anything at all? It can't.
> If the caller wants to make sure some unwind-forms will always run
> after my-function either returns locally or exits non-locally, the
> caller needs to arrange for that.
Unless "the unwind forms" are run by `my-function'. The picture is
still incomplete (and missing the subject of the question).
Michael.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 17:18 ` Spencer Baugh
@ 2024-05-08 20:43 ` Michael Heerdegen via Emacs development discussions.
2024-05-09 12:57 ` Spencer Baugh
0 siblings, 1 reply; 47+ messages in thread
From: Michael Heerdegen via Emacs development discussions. @ 2024-05-08 20:43 UTC (permalink / raw)
To: emacs-devel
Spencer Baugh <sbaugh@janestreet.com> writes:
> > #+begin_src emacs-lisp
> > (let (foo)
> > (while-no-input
> > (unwind-protect (while t nil)
> > (let ((inhibit-quit t))
> > (sleep-for 10)
> > (setq foo 'interrupted)
> > (message "foo: %s" foo)))
> > (message "foo: %s" foo)))
> > #+end_src
> >
> > (unwind forms are not per se protected from nonlocal exiting - see
> > documentation)
>
> That seems to work, but is it robust?
>
> If while-no-input can raise a quit between the start of executing
> unwindforms and the binding of inhibit-quit, then the unwind forms will
> not execute.
AFAIK, unwind forms are always handled, but they can be exited
nonlocally. Above there is only one, and is protected, so I guess it is
save.
> Can while-no-input/throw-on-input actually raise a quit then? And is
> this behavior documented anywhere?
I don't understand the first question. The fact that we protect code
against quitting does not prevent quit being triggered - only in
which way the stack is unwinded...right?
Michael.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 19:28 ` Spencer Baugh
@ 2024-05-09 5:46 ` Eli Zaretskii
2024-05-09 13:07 ` Spencer Baugh
0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2024-05-09 5:46 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Wed, 08 May 2024 15:28:38 -0400
>
> >> How does my-function run the unwind-forms when it is interrupted by
> >> while-no-input?
> >
> > How can a function cause its caller to do anything at all? It can't.
> > If the caller wants to make sure some unwind-forms will always run
> > after my-function either returns locally or exits non-locally, the
> > caller needs to arrange for that.
>
> I don't want to run the unwind forms "after" my-function returns or
> exits. I want them to run wherever they are inside my-function, just
> like a normal unwind-protect.
>
> Let me try to explain again what I want: I want a completely normal
> unwind-protect, exactly how unwind-protect works normally:
>
> (unwind-protect BODYFORM UNWINDFORMS...)
>
> Do BODYFORM, protecting with UNWINDFORMS.
> If BODYFORM completes normally, its value is returned
> after executing the UNWINDFORMS.
> If BODYFORM exits nonlocally, the UNWINDFORMS are executed anyway.
>
> Except that I want the UNWINDFORMS to not be interrupted by a
> *surrounding* while-no-input or quit or any other kind of nonlocal exit.
>
> Is there any way to do that? ("Move the while-no-input inside the
> unwind-protect" is not an answer, because then it's not a *surrounding*
> while-no-input anymore)
IMO, you are trying to solve a problem that is impossible to solve in
general: a function cannot be responsible for the environment in which
it is called. You keep talking about while-no-input, but that's just
an example; there's a virtually infinite number of ways the caller of
your function can call it in a way that thwarts any attempt of yours
to prevent non-local exits. Given enough motivation and effort (and
reliance on the internal implementation details), you could perhaps
fix that single case of calling the function inside while-no-input,
but that will not solve all the rest.
The correct solution to these problems is to document the requirements
of your function from the callers, and let the callers deal with that
according to their needs. (I suspect that in the case that bothers
you, you yourself are that caller, which makes it easier to implement
such protocols.)
Btw, you never explained why you are bothered specifically by
while-no-input. Nor did you describe the problem. Instead, you
describe a solution ("I want a completely normal unwind-protect..."),
and ask us to program such a solution for you without understanding
the problem or the reason why you want to solve it with a "normal
unwind-protect". That is a sure way of making this discussion very
frustrating, if not downright useless. Look how many messages this
thread has already amassed, and how many solutions were proposed, only
to be rejected by you for some reason that was never stated before.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-08 20:43 ` Michael Heerdegen via Emacs development discussions.
@ 2024-05-09 12:57 ` Spencer Baugh
2024-05-09 14:13 ` Michael Heerdegen via Emacs development discussions.
0 siblings, 1 reply; 47+ messages in thread
From: Spencer Baugh @ 2024-05-09 12:57 UTC (permalink / raw)
To: emacs-devel
Michael Heerdegen via "Emacs development discussions."
<emacs-devel@gnu.org> writes:
> Spencer Baugh <sbaugh@janestreet.com> writes:
>
>> > #+begin_src emacs-lisp
>> > (let (foo)
>> > (while-no-input
>> > (unwind-protect (while t nil)
>> > (let ((inhibit-quit t))
>> > (sleep-for 10)
>> > (setq foo 'interrupted)
>> > (message "foo: %s" foo)))
>> > (message "foo: %s" foo)))
>> > #+end_src
>> >
>> > (unwind forms are not per se protected from nonlocal exiting - see
>> > documentation)
>>
>> That seems to work, but is it robust?
>>
>> If while-no-input can raise a quit between the start of executing
>> unwindforms and the binding of inhibit-quit, then the unwind forms will
>> not execute.
>
> AFAIK, unwind forms are always handled, but they can be exited
> nonlocally. Above there is only one, and is protected, so I guess it is
> save.
That unwind-form is only protected once inhibit-quit is bound. But at
the start of its evaluation, it is not protected because inhibit-quit is
not bound. Is it possible for a quit to be raised there, before the
protection starts?
>> Can while-no-input/throw-on-input actually raise a quit then? And is
>> this behavior documented anywhere?
>
> I don't understand the first question. The fact that we protect code
> against quitting does not prevent quit being triggered - only in
> which way the stack is unwinded...right?
>
> Michael.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-09 5:46 ` Eli Zaretskii
@ 2024-05-09 13:07 ` Spencer Baugh
2024-05-09 17:41 ` Dmitry Gutov
` (3 more replies)
0 siblings, 4 replies; 47+ messages in thread
From: Spencer Baugh @ 2024-05-09 13:07 UTC (permalink / raw)
To: emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Spencer Baugh <sbaugh@janestreet.com>
>> Date: Wed, 08 May 2024 15:28:38 -0400
>>
>> >> How does my-function run the unwind-forms when it is interrupted by
>> >> while-no-input?
>> >
>> > How can a function cause its caller to do anything at all? It can't.
>> > If the caller wants to make sure some unwind-forms will always run
>> > after my-function either returns locally or exits non-locally, the
>> > caller needs to arrange for that.
>>
>> I don't want to run the unwind forms "after" my-function returns or
>> exits. I want them to run wherever they are inside my-function, just
>> like a normal unwind-protect.
>>
>> Let me try to explain again what I want: I want a completely normal
>> unwind-protect, exactly how unwind-protect works normally:
>>
>> (unwind-protect BODYFORM UNWINDFORMS...)
>>
>> Do BODYFORM, protecting with UNWINDFORMS.
>> If BODYFORM completes normally, its value is returned
>> after executing the UNWINDFORMS.
>> If BODYFORM exits nonlocally, the UNWINDFORMS are executed anyway.
>>
>> Except that I want the UNWINDFORMS to not be interrupted by a
>> *surrounding* while-no-input or quit or any other kind of nonlocal exit.
>>
>> Is there any way to do that? ("Move the while-no-input inside the
>> unwind-protect" is not an answer, because then it's not a *surrounding*
>> while-no-input anymore)
>
> IMO, you are trying to solve a problem that is impossible to solve in
> general: a function cannot be responsible for the environment in which
> it is called. You keep talking about while-no-input, but that's just
> an example; there's a virtually infinite number of ways the caller of
> your function can call it in a way that thwarts any attempt of yours
> to prevent non-local exits. Given enough motivation and effort (and
> reliance on the internal implementation details), you could perhaps
> fix that single case of calling the function inside while-no-input,
> but that will not solve all the rest.
>
> The correct solution to these problems is to document the requirements
> of your function from the callers, and let the callers deal with that
> according to their needs. (I suspect that in the case that bothers
> you, you yourself are that caller, which makes it easier to implement
> such protocols.)
>
> Btw, you never explained why you are bothered specifically by
> while-no-input. Nor did you describe the problem.
I'm writing a completion-at-point-function and completion table. This
table internally uses asynchronous subprocesses to get completions.
This completion-at-point-function and table may be called by the popular
completion frontend corfu-mode. corfu-mode uses while-no-input around
calls to completion tables.
I want to ensure that my asynchronous subprocesses are deleted even if
my code is interrupted by corfu's while-no-input.
I can't change the protocol of completion tables or
completion-at-point-functions (that's defined by Emacs), and I'm not the
one calling while-no-input (that's corfu-mode).
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-09 12:57 ` Spencer Baugh
@ 2024-05-09 14:13 ` Michael Heerdegen via Emacs development discussions.
0 siblings, 0 replies; 47+ messages in thread
From: Michael Heerdegen via Emacs development discussions. @ 2024-05-09 14:13 UTC (permalink / raw)
To: emacs-devel
Spencer Baugh <sbaugh@janestreet.com> writes:
> That unwind-form is only protected once inhibit-quit is bound. But at
> the start of its evaluation, it is not protected because inhibit-quit is
> not bound. Is it possible for a quit to be raised there, before the
> protection starts?
As far as I understand, this is possible, but Emacs will always start
executing the unwind forms, it will never silently skip them completely.
But my insights here are limited compared to other participants.
Michael.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-09 13:07 ` Spencer Baugh
@ 2024-05-09 17:41 ` Dmitry Gutov
2024-05-11 9:48 ` Eli Zaretskii
` (2 subsequent siblings)
3 siblings, 0 replies; 47+ messages in thread
From: Dmitry Gutov @ 2024-05-09 17:41 UTC (permalink / raw)
To: Spencer Baugh, emacs-devel
On 09/05/2024 16:07, Spencer Baugh wrote:
>> The correct solution to these problems is to document the requirements
>> of your function from the callers, and let the callers deal with that
>> according to their needs. (I suspect that in the case that bothers
>> you, you yourself are that caller, which makes it easier to implement
>> such protocols.)
>>
>> Btw, you never explained why you are bothered specifically by
>> while-no-input. Nor did you describe the problem.
> I'm writing a completion-at-point-function and completion table. This
> table internally uses asynchronous subprocesses to get completions.
>
> This completion-at-point-function and table may be called by the popular
> completion frontend corfu-mode. corfu-mode uses while-no-input around
> calls to completion tables.
>
> I want to ensure that my asynchronous subprocesses are deleted even if
> my code is interrupted by corfu's while-no-input.
>
> I can't change the protocol of completion tables or
> completion-at-point-functions (that's defined by Emacs), and I'm not the
> one calling while-no-input (that's corfu-mode).
And for some extra context: one of the questions at this point is
whether company-mode should also use while-no-input around completion
table queries (for better responsiveness, naturally), or at least
provide an opt-in way to do so.
I wasn't sure there is a safe way to implement completion tables inside
such amended protocol (this is finicky stuff, after all), and suggested
Spencer asks on the mailing list.
The question is specifically about while-no-input, though I suppose any
good solution for it should be safe against C-g too.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-09 13:07 ` Spencer Baugh
2024-05-09 17:41 ` Dmitry Gutov
@ 2024-05-11 9:48 ` Eli Zaretskii
2024-05-11 10:37 ` Eshel Yaron
2024-05-11 10:42 ` Zhengyi Fu
2024-05-14 21:30 ` Dmitry Gutov
3 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2024-05-11 9:48 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> From: Spencer Baugh <sbaugh@janestreet.com>
> Date: Thu, 09 May 2024 09:07:10 -0400
>
> Eli Zaretskii <eliz@gnu.org> writes:
>
> > Btw, you never explained why you are bothered specifically by
> > while-no-input. Nor did you describe the problem.
>
> I'm writing a completion-at-point-function and completion table. This
> table internally uses asynchronous subprocesses to get completions.
>
> This completion-at-point-function and table may be called by the popular
> completion frontend corfu-mode. corfu-mode uses while-no-input around
> calls to completion tables.
>
> I want to ensure that my asynchronous subprocesses are deleted even if
> my code is interrupted by corfu's while-no-input.
Negotiate some protocol with corfu-mode to allow cleanup code to run?
Or maybe the completion machinery already has such protocols defined?
(Because this cannot be the first case where a completion function
needs to clean up, can it?)
Alternatively, run the cleanup from a timer you start in your
completion-at-point-function?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-11 9:48 ` Eli Zaretskii
@ 2024-05-11 10:37 ` Eshel Yaron
0 siblings, 0 replies; 47+ messages in thread
From: Eshel Yaron @ 2024-05-11 10:37 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Spencer Baugh, emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Spencer Baugh <sbaugh@janestreet.com>
>> Date: Thu, 09 May 2024 09:07:10 -0400
>>
>> I'm writing a completion-at-point-function and completion table. This
>> table internally uses asynchronous subprocesses to get completions.
>>
>> This completion-at-point-function and table may be called by the popular
>> completion frontend corfu-mode. corfu-mode uses while-no-input around
>> calls to completion tables.
>>
>> I want to ensure that my asynchronous subprocesses are deleted even if
>> my code is interrupted by corfu's while-no-input.
>
> Negotiate some protocol with corfu-mode to allow cleanup code to run?
Incidentally, we call c-a-p-fs and query completion tables within
while-no-input also in completion-preview-mode. So if there's a need
for some extra accommodations and a protocol is devised for that, it'd
be great if it could be adopted in completion-preview-mode as well.
> Or maybe the completion machinery already has such protocols defined?
> (Because this cannot be the first case where a completion function
> needs to clean up, can it?)
>
> Alternatively, run the cleanup from a timer you start in your
> completion-at-point-function?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-09 13:07 ` Spencer Baugh
2024-05-09 17:41 ` Dmitry Gutov
2024-05-11 9:48 ` Eli Zaretskii
@ 2024-05-11 10:42 ` Zhengyi Fu
2024-05-11 21:45 ` Dmitry Gutov
2024-05-14 21:30 ` Dmitry Gutov
3 siblings, 1 reply; 47+ messages in thread
From: Zhengyi Fu @ 2024-05-11 10:42 UTC (permalink / raw)
To: Spencer Baugh; +Cc: emacs-devel
> I'm writing a completion-at-point-function and completion table. This
> table internally uses asynchronous subprocesses to get completions.
>
> This completion-at-point-function and table may be called by the popular
> completion frontend corfu-mode. corfu-mode uses while-no-input around
> calls to completion tables.
>
> I want to ensure that my asynchronous subprocesses are deleted even if
> my code is interrupted by corfu's while-no-input.
>
> I can't change the protocol of completion tables or
> completion-at-point-functions (that's defined by Emacs), and I'm not the
> one calling while-no-input (that's corfu-mode).
>
Is cape-wrap-noninterruptible from the cape package helpful?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-11 10:42 ` Zhengyi Fu
@ 2024-05-11 21:45 ` Dmitry Gutov
2024-05-11 22:08 ` Daniel Mendler via Emacs development discussions.
0 siblings, 1 reply; 47+ messages in thread
From: Dmitry Gutov @ 2024-05-11 21:45 UTC (permalink / raw)
To: Zhengyi Fu, Spencer Baugh; +Cc: emacs-devel
On 11/05/2024 13:42, Zhengyi Fu wrote:
>> I'm writing a completion-at-point-function and completion table. This
>> table internally uses asynchronous subprocesses to get completions.
>>
>> This completion-at-point-function and table may be called by the popular
>> completion frontend corfu-mode. corfu-mode uses while-no-input around
>> calls to completion tables.
>>
>> I want to ensure that my asynchronous subprocesses are deleted even if
>> my code is interrupted by corfu's while-no-input.
>>
>> I can't change the protocol of completion tables or
>> completion-at-point-functions (that's defined by Emacs), and I'm not the
>> one calling while-no-input (that's corfu-mode).
>>
> Is cape-wrap-noninterruptible from the cape package helpful?
It should help, but it would be odd if any non-trivial completion
function would need to use cape to function inside corfu-mode reliably.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-11 21:45 ` Dmitry Gutov
@ 2024-05-11 22:08 ` Daniel Mendler via Emacs development discussions.
2024-05-12 1:59 ` Dmitry Gutov
0 siblings, 1 reply; 47+ messages in thread
From: Daniel Mendler via Emacs development discussions. @ 2024-05-11 22:08 UTC (permalink / raw)
To: Dmitry Gutov; +Cc: Zhengyi Fu, Spencer Baugh, emacs-devel
Dmitry Gutov <dmitry@gutov.dev> writes:
> On 11/05/2024 13:42, Zhengyi Fu wrote:
>>> I'm writing a completion-at-point-function and completion table. This
>>> table internally uses asynchronous subprocesses to get completions.
>>>
>>> This completion-at-point-function and table may be called by the popular
>>> completion frontend corfu-mode. corfu-mode uses while-no-input around
>>> calls to completion tables.
>>>
>>> I want to ensure that my asynchronous subprocesses are deleted even if
>>> my code is interrupted by corfu's while-no-input.
>>>
>>> I can't change the protocol of completion tables or
>>> completion-at-point-functions (that's defined by Emacs), and I'm not the
>>> one calling while-no-input (that's corfu-mode).
>>>
>> Is cape-wrap-noninterruptible from the cape package helpful?
>
> It should help, but it would be odd if any non-trivial completion function would
> need to use cape to function inside corfu-mode reliably.
cape-wrap-noninterruptible and similarly cape-wrap-silent and
cape-wrap-purify are meant as stop gap measures, used to wrap non-robust
Capfs, until they are improved. There are multiple Capfs in the wild
which regularly print messages or throw unexpected errors. For example,
pcomplete-completions-at-point even modified the buffer until Emacs 29,
which could be mitigated with cape-wrap-purify.
Daniel
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-11 22:08 ` Daniel Mendler via Emacs development discussions.
@ 2024-05-12 1:59 ` Dmitry Gutov
2024-05-12 8:50 ` Daniel Mendler via Emacs development discussions.
0 siblings, 1 reply; 47+ messages in thread
From: Dmitry Gutov @ 2024-05-12 1:59 UTC (permalink / raw)
To: Daniel Mendler; +Cc: Zhengyi Fu, Spencer Baugh, emacs-devel
Hi Daniel,
It's good to see you in this thread.
On 12/05/2024 01:08, Daniel Mendler wrote:
>>> Is cape-wrap-noninterruptible from the cape package helpful?
>> It should help, but it would be odd if any non-trivial completion function would
>> need to use cape to function inside corfu-mode reliably.
> cape-wrap-noninterruptible and similarly cape-wrap-silent and
> cape-wrap-purify are meant as stop gap measures, used to wrap non-robust
> Capfs, until they are improved. There are multiple Capfs in the wild
> which regularly print messages or throw unexpected errors. For example,
> pcomplete-completions-at-point even modified the buffer until Emacs 29,
> which could be mitigated with cape-wrap-purify.
How would such a capf (that has to use cape-wrap-noninterruptible)
usually be improved?
What's your recommendation regarding the necessary cleanup inside the
while-no-input block?
Michael's suggestion --
(let (foo)
(while-no-input
(unwind-protect (while t nil)
(let ((inhibit-quit t))
(sleep-for 10)
(setq foo 'interrupted)
(message "foo: %s" foo)))
(message "foo: %s" foo)))
-- seems to work. Meaning that the interpreter doesn't quit at the
beginning of the unwind block (right before 'let') even when some
pending input exists. But is that a reliable way to write this logic,
i.e. one that both works on all supported platforms and is likely to
survive the potential future optimizations in the Elisp VM?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-12 1:59 ` Dmitry Gutov
@ 2024-05-12 8:50 ` Daniel Mendler via Emacs development discussions.
2024-05-12 11:49 ` Dmitry Gutov
0 siblings, 1 reply; 47+ messages in thread
From: Daniel Mendler via Emacs development discussions. @ 2024-05-12 8:50 UTC (permalink / raw)
To: Dmitry Gutov; +Cc: Zhengyi Fu, Spencer Baugh, emacs-devel
Dmitry Gutov <dmitry@gutov.dev> writes:
> Hi Daniel,
>
> It's good to see you in this thread.
>
> On 12/05/2024 01:08, Daniel Mendler wrote:
>
>>>> Is cape-wrap-noninterruptible from the cape package helpful?
>>> It should help, but it would be odd if any non-trivial completion function would
>>> need to use cape to function inside corfu-mode reliably.
>> cape-wrap-noninterruptible and similarly cape-wrap-silent and
>> cape-wrap-purify are meant as stop gap measures, used to wrap non-robust
>> Capfs, until they are improved. There are multiple Capfs in the wild
>> which regularly print messages or throw unexpected errors. For example,
>> pcomplete-completions-at-point even modified the buffer until Emacs 29,
>> which could be mitigated with cape-wrap-purify.
> What's your recommendation regarding the necessary cleanup inside the
> while-no-input block?
This is a general question, which applies to all situations where
asynchronous exceptions (or user interrupts) occur. One basically has to
protect all critical sections with (let ((throw-on-input nil)
(inhibit-quit t)) ...), which locally disables the exceptions.
Global state manipulations which should not be interrupted, should be
guarded. Most of the Emacs code isn't written in such an exception-safe
way. That's usually okay, as long as the state can still be recovered
somehow after an interrupt by the user. For example if buffer-local
state gets invalid, killing and reopening a buffer will solve the
problem.
However inside Capfs or other code which is very often interrupted,
greater care is necessary. Inside such a critical section, the cleanup
code could be registered somewhere, such that it doesn't get lost. The
cleanup code itself should likely be guarded too.
Daniel
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-12 8:50 ` Daniel Mendler via Emacs development discussions.
@ 2024-05-12 11:49 ` Dmitry Gutov
0 siblings, 0 replies; 47+ messages in thread
From: Dmitry Gutov @ 2024-05-12 11:49 UTC (permalink / raw)
To: Daniel Mendler; +Cc: Zhengyi Fu, Spencer Baugh, emacs-devel
On 12/05/2024 11:50, Daniel Mendler wrote:
>> What's your recommendation regarding the necessary cleanup inside the
>> while-no-input block?
>
> This is a general question, which applies to all situations where
> asynchronous exceptions (or user interrupts) occur. One basically has to
> protect all critical sections with (let ((throw-on-input nil)
> (inhibit-quit t)) ...), which locally disables the exceptions.
Okay, sure.
> Global state manipulations which should not be interrupted, should be
> guarded. Most of the Emacs code isn't written in such an exception-safe
> way. That's usually okay, as long as the state can still be recovered
> somehow after an interrupt by the user. For example if buffer-local
> state gets invalid, killing and reopening a buffer will solve the
> problem.
>
> However inside Capfs or other code which is very often interrupted,
> greater care is necessary. Inside such a critical section, the cleanup
> code could be registered somewhere, such that it doesn't get lost. The
> cleanup code itself should likely be guarded too.
So what is the way you prefer the original example would be improved?
Like Michael suggested (and I quoted), or some other way?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-09 13:07 ` Spencer Baugh
` (2 preceding siblings ...)
2024-05-11 10:42 ` Zhengyi Fu
@ 2024-05-14 21:30 ` Dmitry Gutov
2024-05-26 2:49 ` Stefan Monnier via Emacs development discussions.
3 siblings, 1 reply; 47+ messages in thread
From: Dmitry Gutov @ 2024-05-14 21:30 UTC (permalink / raw)
To: Spencer Baugh, emacs-devel, Stefan Monnier
Perhaps Stefan has something to add on this subject as well?
To rephrase, does it sound like a good idea to wrap completion table
queries in (while-no-input ...) by default (another option is making it
opt-in), and what would be the best implementation choice for a
"cleanup" block when your code is inside while-no-input.
On 09/05/2024 16:07, Spencer Baugh wrote:
>> The correct solution to these problems is to document the requirements
>> of your function from the callers, and let the callers deal with that
>> according to their needs. (I suspect that in the case that bothers
>> you, you yourself are that caller, which makes it easier to implement
>> such protocols.)
>>
>> Btw, you never explained why you are bothered specifically by
>> while-no-input. Nor did you describe the problem.
> I'm writing a completion-at-point-function and completion table. This
> table internally uses asynchronous subprocesses to get completions.
>
> This completion-at-point-function and table may be called by the popular
> completion frontend corfu-mode. corfu-mode uses while-no-input around
> calls to completion tables.
>
> I want to ensure that my asynchronous subprocesses are deleted even if
> my code is interrupted by corfu's while-no-input.
>
> I can't change the protocol of completion tables or
> completion-at-point-functions (that's defined by Emacs), and I'm not the
> one calling while-no-input (that's corfu-mode).
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-07 18:05 ` Spencer Baugh
2024-05-07 18:49 ` Eli Zaretskii
@ 2024-05-26 2:47 ` Stefan Monnier via Emacs development discussions.
2024-05-26 4:36 ` Stefan Monnier
2024-05-26 4:55 ` Eli Zaretskii
1 sibling, 2 replies; 47+ messages in thread
From: Stefan Monnier via Emacs development discussions. @ 2024-05-26 2:47 UTC (permalink / raw)
To: emacs-devel
> It seems like it's impossible right now to use unwind-protect robustly
> in face of quits, because a quit triggered in the body forms of the
> unwind-protect will also interrupt the unwind forms.
I believe that is indeed the case. 🙁
> And there is no way to work around this, because binding inhibit-quit
> in the unwind forms can *also* be interrupted.
Yup. I have seen such problems when I hit `C-g` frantically to get out
of some problematic state, and some of the repetitions end up happening
while we're running the unwind forms.
> Maybe there should be a version of unwind-protect which automatically
> and atomically inhibits quit in the unwind forms?
I tend to agree. I even considered that this should apply to all unwind
forms, tho I suspect it would be too drastic, making it impossible to
escape problems where the unwind form itself is stuck in an inf-loop.
At the very least things like `C-g` should not be able to interrupt the
unwinding of things like dynamically scoped let-bindings or
`save-excursion`.
Is there a bug-report associated to this thread?
Maybe a "cheaper" answer for your specific problem is to make sure
that once `while-no-input` has started a non-local exit (which it does
with `throw`, IIRC), we mark "this while-no-input" as being done
so it won't cause a nested exit while we process the unwind form of the
original exit.
E.g. with a patch like the one below? Would it fix your case?
Stefan
diff --git a/src/keyboard.c b/src/keyboard.c
index 3551a77a9c9..c2c326f434c 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -3801,7 +3816,10 @@ kbd_buffer_store_buffered_event (union buffered_input_event *event,
as input, set quit-flag to cause an interrupt. */
if (!NILP (Vthrow_on_input)
&& !is_ignored_event (event))
- Vquit_flag = Vthrow_on_input;
+ {
+ Vquit_flag = Vthrow_on_input;
+ Vthrow_on_input = !nil;
+ }
}
/* Limit help event positions to this range, to avoid overflow problems. */
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-14 21:30 ` Dmitry Gutov
@ 2024-05-26 2:49 ` Stefan Monnier via Emacs development discussions.
2024-05-26 15:36 ` Dmitry Gutov
0 siblings, 1 reply; 47+ messages in thread
From: Stefan Monnier via Emacs development discussions. @ 2024-05-26 2:49 UTC (permalink / raw)
To: emacs-devel
> To rephrase, does it sound like a good idea to wrap completion table queries
> in (while-no-input ...) by default
As a general rule, no. It only makes sense in some specific circumstances.
> (another option is making it opt-in), and
> what would be the best implementation choice for a "cleanup" block when your
> code is inside while-no-input.
That's what `unwind-protect` should be for.
And if it doesn't work, we should fix that.
Stefan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-26 2:47 ` Stefan Monnier via Emacs development discussions.
@ 2024-05-26 4:36 ` Stefan Monnier
2024-05-26 4:55 ` Eli Zaretskii
1 sibling, 0 replies; 47+ messages in thread
From: Stefan Monnier @ 2024-05-26 4:36 UTC (permalink / raw)
To: Stefan Monnier via Emacs development discussions.
> E.g. with a patch like the one below? Would it fix your case?
Nah, that one can't work. But maybe the one below?
Stefan
diff --git a/src/eval.c b/src/eval.c
index 1386ff3e764..38803ad8f5f 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1726,7 +1726,10 @@ process_quit_flag (void)
if (EQ (flag, Qkill_emacs))
Fkill_emacs (Qnil, Qnil);
if (EQ (Vthrow_on_input, flag))
- Fthrow (Vthrow_on_input, Qt);
+ {
+ Vthrow_on_input = Qnil;
+ Fthrow (flag, Qt);
+ }
if (CONSP (flag)
&& 4 == XFIXNUM (Flength (flag))
&& EQ (XCAR (flag), Vdebug_on_event))
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-26 2:47 ` Stefan Monnier via Emacs development discussions.
2024-05-26 4:36 ` Stefan Monnier
@ 2024-05-26 4:55 ` Eli Zaretskii
2024-05-26 18:12 ` Stefan Monnier
1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2024-05-26 4:55 UTC (permalink / raw)
To: Stefan Monnier; +Cc: emacs-devel
> Date: Sat, 25 May 2024 22:47:07 -0400
> From: Stefan Monnier via "Emacs development discussions." <emacs-devel@gnu.org>
>
> Maybe a "cheaper" answer for your specific problem is to make sure
> that once `while-no-input` has started a non-local exit (which it does
> with `throw`, IIRC), we mark "this while-no-input" as being done
> so it won't cause a nested exit while we process the unwind form of the
> original exit.
>
> E.g. with a patch like the one below? Would it fix your case?
Please don't install anything like this until the emacs-30 release
branch is cut.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-26 2:49 ` Stefan Monnier via Emacs development discussions.
@ 2024-05-26 15:36 ` Dmitry Gutov
2024-05-26 18:00 ` Stefan Monnier
0 siblings, 1 reply; 47+ messages in thread
From: Dmitry Gutov @ 2024-05-26 15:36 UTC (permalink / raw)
To: Stefan Monnier, emacs-devel
On 26/05/2024 05:49, Stefan Monnier via Emacs development discussions.
wrote:
>> To rephrase, does it sound like a good idea to wrap completion table queries
>> in (while-no-input ...) by default
>
> As a general rule, no. It only makes sense in some specific circumstances.
All right. Would you say that the general class of circumstances like
- completion is performed when Emacs is idle
- non-essential is t
- called by icomplete to show completion hints
is a good general rule to apply while-no-input?
Or did you mean more like the ways completion is implemented? E.g. if
it's entirely in Lisp, while-no-input is fine; external processes -
maybe not. That sort of thing.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-26 15:36 ` Dmitry Gutov
@ 2024-05-26 18:00 ` Stefan Monnier
2024-05-26 22:56 ` Dmitry Gutov
0 siblings, 1 reply; 47+ messages in thread
From: Stefan Monnier @ 2024-05-26 18:00 UTC (permalink / raw)
To: Dmitry Gutov; +Cc: emacs-devel
> All right. Would you say that the general class of circumstances like
>
> - completion is performed when Emacs is idle
> - non-essential is t
> - called by icomplete to show completion hints
>
> is a good general rule to apply while-no-input?
Yes, basically the choice should be made on the UI side. The completion
table itself doesn't know why the caller wants the info so it can't know
whether user input makes the request pointless.
Stefan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-26 4:55 ` Eli Zaretskii
@ 2024-05-26 18:12 ` Stefan Monnier
0 siblings, 0 replies; 47+ messages in thread
From: Stefan Monnier @ 2024-05-26 18:12 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
> Please don't install anything like this until the emacs-30 release
> branch is cut.
Yeah, we don't even know if it fixes the problem 🙂
Stefan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-26 18:00 ` Stefan Monnier
@ 2024-05-26 22:56 ` Dmitry Gutov
2024-05-29 0:39 ` Stefan Monnier
0 siblings, 1 reply; 47+ messages in thread
From: Dmitry Gutov @ 2024-05-26 22:56 UTC (permalink / raw)
To: Stefan Monnier; +Cc: emacs-devel
On 26/05/2024 21:00, Stefan Monnier wrote:
>> All right. Would you say that the general class of circumstances like
>>
>> - completion is performed when Emacs is idle
>> - non-essential is t
>> - called by icomplete to show completion hints
>>
>> is a good general rule to apply while-no-input?
> Yes, basically the choice should be made on the UI side. The completion
> table itself doesn't know why the caller wants the info so it can't know
> whether user input makes the request pointless.
Yeah, definitely. I was just wondering whether we should make that
choice entirely in the UI, or make it additionally opt-in for completion
tables (telling the UI that it's fine with such treatment).
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-26 22:56 ` Dmitry Gutov
@ 2024-05-29 0:39 ` Stefan Monnier
2024-05-29 1:17 ` Dmitry Gutov
0 siblings, 1 reply; 47+ messages in thread
From: Stefan Monnier @ 2024-05-29 0:39 UTC (permalink / raw)
To: Dmitry Gutov; +Cc: emacs-devel
>>> All right. Would you say that the general class of circumstances like
>>>
>>> - completion is performed when Emacs is idle
>>> - non-essential is t
>>> - called by icomplete to show completion hints
>>>
>>> is a good general rule to apply while-no-input?
>> Yes, basically the choice should be made on the UI side. The completion
>> table itself doesn't know why the caller wants the info so it can't know
>> whether user input makes the request pointless.
>
> Yeah, definitely. I was just wondering whether we should make that choice
> entirely in the UI, or make it additionally opt-in for completion tables
> (telling the UI that it's fine with such treatment).
Maybe it would be useful for completion tables to be able to tell the
UI whether `while-no-input` is "supported", but I'm not sure we have
enough evidence to suggest it would be useful.
BTW, in practice completion tables can already "override" a UI's
`while-no-input`, if necessary, by rebinding `throw-on-input` to nil.
Stefan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: unwind-protect within while-no-input
2024-05-29 0:39 ` Stefan Monnier
@ 2024-05-29 1:17 ` Dmitry Gutov
0 siblings, 0 replies; 47+ messages in thread
From: Dmitry Gutov @ 2024-05-29 1:17 UTC (permalink / raw)
To: Stefan Monnier; +Cc: emacs-devel
On 29/05/2024 03:39, Stefan Monnier wrote:
>>>> All right. Would you say that the general class of circumstances like
>>>>
>>>> - completion is performed when Emacs is idle
>>>> - non-essential is t
>>>> - called by icomplete to show completion hints
>>>>
>>>> is a good general rule to apply while-no-input?
>>> Yes, basically the choice should be made on the UI side. The completion
>>> table itself doesn't know why the caller wants the info so it can't know
>>> whether user input makes the request pointless.
>> Yeah, definitely. I was just wondering whether we should make that choice
>> entirely in the UI, or make it additionally opt-in for completion tables
>> (telling the UI that it's fine with such treatment).
> Maybe it would be useful for completion tables to be able to tell the
> UI whether `while-no-input` is "supported", but I'm not sure we have
> enough evidence to suggest it would be useful.
>
> BTW, in practice completion tables can already "override" a UI's
> `while-no-input`, if necessary, by rebinding `throw-on-input` to nil.
Okay, that makes sense.
I guess it's more of a backward compatibility concern - how some
(possibly many) existing completion tables might start misbehaving after
the new release of company-mode, and some one of them might not have a
dedicated maintainer these days.
The popularity of Corfu and icomplete indicates that it's mostly fine.
OTOH, some conservative users (who would otherwise have problems with
while-no-input) might just be staying with company-mode because of
stronger backward compat.
Buuut... I guess I could flip the switch and wait for reports, as usual.
^ permalink raw reply [flat|nested] 47+ messages in thread
end of thread, other threads:[~2024-05-29 1:17 UTC | newest]
Thread overview: 47+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-03 12:45 unwind-protect within while-no-input Spencer Baugh
2024-05-07 18:05 ` Spencer Baugh
2024-05-07 18:49 ` Eli Zaretskii
2024-05-07 19:43 ` Spencer Baugh
2024-05-08 3:59 ` Po Lu
2024-05-08 11:42 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 11:47 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 13:44 ` Spencer Baugh
2024-05-08 16:13 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 17:18 ` Spencer Baugh
2024-05-08 20:43 ` Michael Heerdegen via Emacs development discussions.
2024-05-09 12:57 ` Spencer Baugh
2024-05-09 14:13 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 12:12 ` Eli Zaretskii
2024-05-08 12:36 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 11:52 ` Eli Zaretskii
2024-05-08 13:57 ` Spencer Baugh
2024-05-08 14:18 ` Eli Zaretskii
2024-05-08 14:38 ` Spencer Baugh
2024-05-08 15:06 ` Eli Zaretskii
2024-05-08 15:14 ` Spencer Baugh
2024-05-08 18:51 ` Eli Zaretskii
2024-05-08 19:28 ` Spencer Baugh
2024-05-09 5:46 ` Eli Zaretskii
2024-05-09 13:07 ` Spencer Baugh
2024-05-09 17:41 ` Dmitry Gutov
2024-05-11 9:48 ` Eli Zaretskii
2024-05-11 10:37 ` Eshel Yaron
2024-05-11 10:42 ` Zhengyi Fu
2024-05-11 21:45 ` Dmitry Gutov
2024-05-11 22:08 ` Daniel Mendler via Emacs development discussions.
2024-05-12 1:59 ` Dmitry Gutov
2024-05-12 8:50 ` Daniel Mendler via Emacs development discussions.
2024-05-12 11:49 ` Dmitry Gutov
2024-05-14 21:30 ` Dmitry Gutov
2024-05-26 2:49 ` Stefan Monnier via Emacs development discussions.
2024-05-26 15:36 ` Dmitry Gutov
2024-05-26 18:00 ` Stefan Monnier
2024-05-26 22:56 ` Dmitry Gutov
2024-05-29 0:39 ` Stefan Monnier
2024-05-29 1:17 ` Dmitry Gutov
2024-05-08 20:34 ` Michael Heerdegen via Emacs development discussions.
2024-05-08 16:17 ` Michael Heerdegen via Emacs development discussions.
2024-05-26 2:47 ` Stefan Monnier via Emacs development discussions.
2024-05-26 4:36 ` Stefan Monnier
2024-05-26 4:55 ` Eli Zaretskii
2024-05-26 18:12 ` Stefan Monnier
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.