Subject: Re: bug#78946: 30.1; accept-process-output not allowed in threads on macOS

From: Alan Third <[email-masked]>
Date: Mon, 7 Jul 2025 21:47:09 +0100

On Mon, Jul 07, 2025 at 11:28:18AM +0200, Robert Pluim wrote:
> 
> I really donʼt get it either: on macOS we run an infinite loop in
> `fd_handler', that gets sent messages via a pipe by `ns_select_1' to
> run `pselect' (previously only if `ns_select_1' was called from the
> main thread, but now all the time).
> 
> But apparently itʼs ok to call `pselect' directly (via
> `thread_select') from a non-main thread (which is why previously that
> return was there for that case).
> 
> Itʼs not ok to call the macOS run loop from a non-main thread, which
> is where Johnʼs problems came from, but we have to run the run loop
> because `fd_handler' returns information using macOS events.
> 
> Perhaps we could use a second pipe instead? It would remove the
> requirement to go via the macOS event loop, I think.
> 
> I think more coffee is needed 😀

OK, the fd_handler thread only exists because we "need" to run the NS
run loop and pselect simultaneously. Obviously we can't do that with a
single thread, so one has to be put into a separate thread. The
fd_handler only communicates with the run loop in as much as it tells
it to stop. All it's actual *results* are handed back via the global
variables select_readfds, select_writefds, etc.

So there's nothing special about running pselect in the main thread
here, it's just not done because the run loop is required at the same
time.

This means that if we decide we don't need to run the run loop (which
is something we used to do) then we could just call thread_select. And
just to confuse matters we have to run thread_select anyway, as that's
how Emacs chooses to run another lisp thread. So you'll see a call
near the top of the ns_select function with a zero timeout and we just
ignore the return value.

Sub-threads, as you say, can't call the run loop, so for them
ns_select should act pretty much just like a call to pselect.

Ultimately, ns_select should look to the caller just like a call to
pselect, or whatever. It should return whatever pselect would return
in that situation, and shouldn't behave differently, although you and
I know it's doing a whole bunch of other stuff behind the caller's
back.

I scare quoted "need" above because the reality is that we don't
actually *need* to run the run loop in ns_select, it's just a
convenient place for it.

The ideal situation would be for the run loop to run in it's own
thread and ns_select could then be replaced with a simple call to
thread_select like some of the other terms.

But implementing that comes with it's own set of nightmares.

Another approach I looked at briefly to simplify this is emulating
pselect in the run loop. It can monitor the read fds, but not the
write fds, so I gave up on that.
-- 
Alan Third