Subject: Re: bug#76969: kill-buffer fails silently when a thread exists where it's current

From: Dmitry Gutov <[email-masked]>
Date: Tue, 18 Mar 2025 02:07:57 +0200

On 16/03/2025 08:07, Eli Zaretskii wrote:

>> I wonder if the set of functions which behave safely under such
>> conditions is large enough for this to be the default.
> 
> If someone would like to make a survey of use patterns of Lisp
> threads, I think it will be useful in more than one way.

Here's a minor survey: among the packages I have installed there are 2 
(!) which use threads, out of 55: lsp-mode and diff-hl, the latter has 
triggered this discussion.

In GNU ELPA, there are also phpinspect, debbugs and phps-mode.

>>>> We can't really distinguish between these kinds of threads from the
>>>> outside, so the general model would need to err on the side of safety.
>>>
>>> The side of safety in my book is not to kill the buffer.  You
>>> suggested instead to signal the thread, which would terminate it, and
>>> I consider that not erring on the side of safety.
>>
>> Okay... then by default we will not kill the buffer, but allow threads
>> to opt into allowing the buffer to be killed, preceded by a signal?
>>
>> That sounds safe enough.
> 
> I actually thought the other way around: kill the buffer and deliver
> the signal, unless a special buffer-local variable is non-nil.

This sounds like the same description, with the only difference that the 
said variable is nil by default.

If so, sounds good to me.

>> But the downside is we retain the current issue, right? As described in
>> the original report.
> 
> With your default, yes.  OTOH, the original report didn't explain why
> not killing the buffer is a problem.

Unpredictability, lack of observability, poor debugging. Mentioned all 
these in the first few messages.

> In general, any Lisp program
> that calls kill-buffer should be prepared to deal with the fact that
> the buffer might not be killed, due to any of the possible reasons
> which prevent that already, even if other threads are no involved.

Most of which have stayed documented thus far.

In any case, as I said in the beginning, we don't have to kill the 
buffer, but then we should consider other ways of making it clearer why 
it wasn't killed (to the programmers, to the users).

Having the "kill and signal" default would be easier conceptually.

>>>> Not sure what thread function you're thinking of in this case.
>>>
>>> In this analogy, showing buffers is that "thread function".
>>
>> Okay. So take just a function that is going to display a buffer. If the
>> buffer is killed, wouldn't it be better for the
> 
> This sentence seems to be unfinished.

Sorry.

...would it be better for the "show buffer" function to be interrupted, 
rather than have it show a different buffer?

This question might be moot already, if we agree that "kill" and 
"signal" should go together in our scenario (either both happen or neither).

>> I was unclear if you think it's better to always kill the buffer, or to
>> have that behavior opt-in.
> 
> That's because I don't yet have a firm opinion.  And to some extent
> that depends on the optional features we will implement:
> 
>   . is signal always delivered or only to threads which said they want it?
>   . do we add a buffer-local dont-ever-kill-my-buffer variable?

The difference between these option is really whether the behavior is 
off or no by default, right?

As for whether it's a thread property or a local var, either seems 
workable to me.

>> If the buffer is killed, though, I believe it is better to signal its
>> threads. Having the buffer substituted can easily get unnoticed, and
>> would be hard to debug.
> 
> And I tend to prefer leaving this to the Lisp program which starts the
> thread, via an additional argument to make-thread.

I don't think we could make the argument a required one. And as long as 
it isn't, the question of default stays relevant.