[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: continuation passing in Emacs vs. JUST-THIS-ONE

From: Lynn Winebarger
Subject: Re: continuation passing in Emacs vs. JUST-THIS-ONE
Date: Sun, 16 Apr 2023 23:46:30 -0400

On Wed, Mar 29, 2023 at 2:48 PM Stefan Monnier <monnier@iro.umontreal.ca> wrote:
> >> Part of the issue is the management of `current-buffer`: should the
> >> composition of futures with `futur-let*` save&restore
> >> `current-buffer` to mimic more closely the behavior one would get
> >> with plain old sequential execution?  If so, should we do the same
> >> with `point`?  What about other such state?
> >
> > I do not think there is a good implicit solution.
> > Either it would save too much state or too little,
> > or save it the wrong way.
> Currently it doesn't save anything, which is "ideal" in terms of
> efficiency, but sometimes leads to code that's more verbose than
> I'd like.
> Someone suggested to save as much as threads do, but that's not
> practical.

This whole thread seems to echo the difference between "stackless" and
"stackful" coroutines discussed in
https://nullprogram.com/blog/2019/03/10/ by the author of emacs-aio,
with generator-style rewriting corresponding to stackless and threads
to "stackful".  So when you say "save as much as threads do", I'm not
clear if you're talking about rewriting code to essentially create a
heap allocated version of the same information that a thread has in
the form of its stack, or something more limited like some particular
set of special bindings.

It seems to me what one would really like is for primitives that might
block to just return a future that's treated like any other value,
except that "futurep" would return true and primitive operations would
implicitly wait on the futures in their arguments.  But making
something like that work would require extensive reengineering of
emacs internals.

Looking at src/thread.c, it appears emacs threads are just thin layer
over system threads with a global lock.  An alternative would be to
use a basic user-space cooperative threading implementation running on
top of the system threads, which would simply run a trampoline to
whatever user space thread was assigned to it.  The user space threads
would not be locked to any particular system thread, but go back to
the queue of some emacs-owned scheduler after yielding control.  Then
if a primitive will block, it could switch to a fresh user-space
thread running in the same user-space thread, put a future that
references this new thread in the continuation for the original thread
(which is placed back in emacs's scheduler queue), then give up the
GIL before making the blocking call on the system thread.  Then the
emacs scheduler would choose some available system thread in its pool
and dispatch the next user space continuation to it, eventually
redispatching the original user-space thread.  The whole sequence
would play out again if a primitive operation blocked trying to read
the value of the first future.

I think that would provide the asynchronous but not concurrent
semantics you're talking about.  But it would be a lot of work.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]