unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Blocking calls and threads
@ 2023-04-20  5:31 Lynn Winebarger
  2023-04-20  7:00 ` Po Lu
  2023-04-20  7:23 ` Eli Zaretskii
  0 siblings, 2 replies; 11+ messages in thread
From: Lynn Winebarger @ 2023-04-20  5:31 UTC (permalink / raw)
  To: emacs-devel

The thread on how to make asynchronous behavior explicit made me
curious whether making a blocking system call would cause the lisp
thread to yield to other lisp threads (release the global lock).  Do
blocking system calls yield the lisp thread, or is there any way in
lisp code to call blocking functions so that the lisp thread will
yield while the system thread blocks?

Thanks,
Lynn



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Blocking calls and threads
  2023-04-20  5:31 Blocking calls and threads Lynn Winebarger
@ 2023-04-20  7:00 ` Po Lu
  2023-04-20  7:23 ` Eli Zaretskii
  1 sibling, 0 replies; 11+ messages in thread
From: Po Lu @ 2023-04-20  7:00 UTC (permalink / raw)
  To: Lynn Winebarger; +Cc: emacs-devel

Lynn Winebarger <owinebar@gmail.com> writes:

> The thread on how to make asynchronous behavior explicit made me
> curious whether making a blocking system call would cause the lisp
> thread to yield to other lisp threads (release the global lock).  Do
> blocking system calls yield the lisp thread, or is there any way in
> lisp code to call blocking functions so that the lisp thread will
> yield while the system thread blocks?

System calls don't currently yield the Lisp thread, apart from pselect.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Blocking calls and threads
  2023-04-20  5:31 Blocking calls and threads Lynn Winebarger
  2023-04-20  7:00 ` Po Lu
@ 2023-04-20  7:23 ` Eli Zaretskii
  2023-04-20 13:06   ` Lynn Winebarger
  1 sibling, 1 reply; 11+ messages in thread
From: Eli Zaretskii @ 2023-04-20  7:23 UTC (permalink / raw)
  To: Lynn Winebarger; +Cc: emacs-devel

> From: Lynn Winebarger <owinebar@gmail.com>
> Date: Thu, 20 Apr 2023 01:31:14 -0400
> 
> The thread on how to make asynchronous behavior explicit made me
> curious whether making a blocking system call would cause the lisp
> thread to yield to other lisp threads (release the global lock).  Do
> blocking system calls yield the lisp thread, or is there any way in
> lisp code to call blocking functions so that the lisp thread will
> yield while the system thread blocks?

What do you mean by "blocking system calls", exactly?

If you mean the likes of 'read' and 'write' (i.e. "blocking system
calls" on the OS level), then no, a thread which makes these calls
will not yield.  How can it? the implementation of those calls is not
in Emacs, so how can Emacs change the way these syscalls work?

The "blocking system calls" which do yield are calls emitted from
Lisp: accept-process-output, sit-for, read-key-sequence, etc.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Blocking calls and threads
  2023-04-20  7:23 ` Eli Zaretskii
@ 2023-04-20 13:06   ` Lynn Winebarger
  2023-04-20 13:28     ` Po Lu
  2023-04-20 13:37     ` Eli Zaretskii
  0 siblings, 2 replies; 11+ messages in thread
From: Lynn Winebarger @ 2023-04-20 13:06 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On Thu, Apr 20, 2023 at 3:23 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Lynn Winebarger <owinebar@gmail.com>
> > Date: Thu, 20 Apr 2023 01:31:14 -0400
> >
> > The thread on how to make asynchronous behavior explicit made me
> > curious whether making a blocking system call would cause the lisp
> > thread to yield to other lisp threads (release the global lock).  Do
> > blocking system calls yield the lisp thread, or is there any way in
> > lisp code to call blocking functions so that the lisp thread will
> > yield while the system thread blocks?
>
> What do you mean by "blocking system calls", exactly?
>
> If you mean the likes of 'read' and 'write' (i.e. "blocking system
> calls" on the OS level),

Almost - I mean the subrs that make those operations available to the
lisp machine, e.g. insert-file-contents.

> then no, a thread which makes these calls
> will not yield.  How can it? the implementation of those calls is not
> in Emacs, so how can Emacs change the way these syscalls work?

Presumably whatever mechanism is used for the calls you identified
below could be generalized.  In practical terms, it would mean
assigning locks to every system resource that isn't inherently part of
the lisp machine, in this case at least file descriptors.  Then, for
example, the read call in emacs_intr_read (in sysdep.c) could be
surrounded by a release of the global lock (which yields the thread of
the lisp machine) and the re-acquisition of the global lock.  The file
descriptor lock might be acquired after yielding the lisp thread, or
it might be owned exclusively by the thread that opened it.

>
> The "blocking system calls" which do yield are calls emitted from
> Lisp: accept-process-output, sit-for, read-key-sequence, etc.

Are these identified as a group anywhere for reference?  Otherwise, I
don't know what is included in the "etc".

Thanks,
Lynn



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Blocking calls and threads
  2023-04-20 13:06   ` Lynn Winebarger
@ 2023-04-20 13:28     ` Po Lu
  2023-04-20 14:26       ` Lynn Winebarger
  2023-04-20 13:37     ` Eli Zaretskii
  1 sibling, 1 reply; 11+ messages in thread
From: Po Lu @ 2023-04-20 13:28 UTC (permalink / raw)
  To: Lynn Winebarger; +Cc: Eli Zaretskii, emacs-devel

Lynn Winebarger <owinebar@gmail.com> writes:

> Presumably whatever mechanism is used for the calls you identified
> below could be generalized.  In practical terms, it would mean
> assigning locks to every system resource that isn't inherently part of
> the lisp machine, in this case at least file descriptors.  Then, for
> example, the read call in emacs_intr_read (in sysdep.c) could be
> surrounded by a release of the global lock (which yields the thread of
> the lisp machine) and the re-acquisition of the global lock.  The file
> descriptor lock might be acquired after yielding the lisp thread, or
> it might be owned exclusively by the thread that opened it.

I'm afraid that's not so easy.  Parts of Emacs have certainly been
designed with the assumption that context switching cannot happen inside
read and friends; at least the Android and NS ports have this problem.

> Are these identified as a group anywhere for reference?  Otherwise, I
> don't know what is included in the "etc".

Basically anything that calls `thread_select'.  This includes almost
everything that waits for input.  Please grep around in the C sources.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Blocking calls and threads
  2023-04-20 13:06   ` Lynn Winebarger
  2023-04-20 13:28     ` Po Lu
@ 2023-04-20 13:37     ` Eli Zaretskii
  2023-04-20 14:19       ` Lynn Winebarger
  1 sibling, 1 reply; 11+ messages in thread
From: Eli Zaretskii @ 2023-04-20 13:37 UTC (permalink / raw)
  To: Lynn Winebarger; +Cc: emacs-devel

> From: Lynn Winebarger <owinebar@gmail.com>
> Date: Thu, 20 Apr 2023 09:06:16 -0400
> Cc: emacs-devel@gnu.org
> 
> > What do you mean by "blocking system calls", exactly?
> >
> > If you mean the likes of 'read' and 'write' (i.e. "blocking system
> > calls" on the OS level),
> 
> Almost - I mean the subrs that make those operations available to the
> lisp machine, e.g. insert-file-contents.

insert-file-contents does a lot of simple bookkeeping stuff, then
calls 'read' in a loop to read the file and decode the stuff it reads.
We could perhaps yield between reading and processing chunks (we don't
in the current Emacs), but would it help?  Modern systems are very
fast in reading local files, so you'd make insert-file-contents and
its callers much slower for no good reason.  Likewise in write-region.

> > then no, a thread which makes these calls
> > will not yield.  How can it? the implementation of those calls is not
> > in Emacs, so how can Emacs change the way these syscalls work?
> 
> Presumably whatever mechanism is used for the calls you identified
> below could be generalized.  In practical terms, it would mean
> assigning locks to every system resource that isn't inherently part of
> the lisp machine, in this case at least file descriptors.  Then, for
> example, the read call in emacs_intr_read (in sysdep.c) could be
> surrounded by a release of the global lock (which yields the thread of
> the lisp machine) and the re-acquisition of the global lock.  The file
> descriptor lock might be acquired after yielding the lisp thread, or
> it might be owned exclusively by the thread that opened it.

If you yield before issuing the system call, the system call will wait
until you re-acquire the lock.  So how will this help?

To be effective, this needs to yield _after_ issuing the system call,
so that the system call proceeds in parallel with Emacs doing
something else.  But since the system call is not implemented by
Emacs, I don't see how this could be done?  In a new non-Lisp thread
that we would start to issue the system call from it? is that what you
have in mind?  But then we'd have the "usual" problem with Emacs: the
huge global state that we have.  That non-Lisp thread cannot use any
machinery that changes the global state, nor call any Lisp or Lisp
primitives, so it will only be able to do very simple processing, thus
making the whole business much less beneficial, from the user's POV.

> > The "blocking system calls" which do yield are calls emitted from
> > Lisp: accept-process-output, sit-for, read-key-sequence, etc.
> 
> Are these identified as a group anywhere for reference?  Otherwise, I
> don't know what is included in the "etc".

Basically, anything that ends up calling thread_select, usually via
wait_reading_process_output.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Blocking calls and threads
  2023-04-20 13:37     ` Eli Zaretskii
@ 2023-04-20 14:19       ` Lynn Winebarger
  2023-04-20 14:36         ` Eli Zaretskii
  0 siblings, 1 reply; 11+ messages in thread
From: Lynn Winebarger @ 2023-04-20 14:19 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On Thu, Apr 20, 2023 at 9:37 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Lynn Winebarger <owinebar@gmail.com>
> > Date: Thu, 20 Apr 2023 09:06:16 -0400
> > Cc: emacs-devel@gnu.org
> >
> > > What do you mean by "blocking system calls", exactly?
> > >
> > > If you mean the likes of 'read' and 'write' (i.e. "blocking system
> > > calls" on the OS level),
> >
> > Almost - I mean the subrs that make those operations available to the
> > lisp machine, e.g. insert-file-contents.
>
> insert-file-contents does a lot of simple bookkeeping stuff, then
> calls 'read' in a loop to read the file and decode the stuff it reads.
> We could perhaps yield between reading and processing chunks (we don't
> in the current Emacs), but would it help?  Modern systems are very
> fast in reading local files, so you'd make insert-file-contents and
> its callers much slower for no good reason.  Likewise in write-region.

I don't know whether it's a good idea.  I'm not sure how anyone can
work out how to provide explicit but generic asynchronous programming
constructs, as Stefan is, when some operations are implemented in ways
that don't allow it.

>
> If you yield before issuing the system call, the system call will wait
> until you re-acquire the lock.  So how will this help?

You're talking about yielding the system thread, I'm talking about
yielding the Lisp machine thread.  Even though Lisp machine threads
are implemented by mapping them to the underlying system thread,  the
Lisp machine execution state is kept coherent by the global
(interpreter) lock.  Releasing the lock is effectively yielding the
Lisp machine thread.  The system thread will yield implicitly if the
read blocks.

>
> To be effective, this needs to yield _after_ issuing the system call,
> so that the system call proceeds in parallel with Emacs doing
> something else.  But since the system call is not implemented by
> Emacs, I don't see how this could be done?  In a new non-Lisp thread
> that we would start to issue the system call from it? is that what you
> have in mind?  But then we'd have the "usual" problem with Emacs: the
> huge global state that we have.  That non-Lisp thread cannot use any
> machinery that changes the global state, nor call any Lisp or Lisp
> primitives, so it will only be able to do very simple processing, thus
> making the whole business much less beneficial, from the user's POV.

So making "insert-file-contents" yield would introduce race conditions
with respect to the buffer being read into that the lisp programmer
choosing to use threads would have to be responsible for (which would
be what Stefan is trying to simplify, I think).  I don't mean
lisp-machine violating race conditions - the read operation should
either use some temporary buffer and copy into the lisp buffer, or
wait for data to be ready, then reacquire the GIL before invoking the
read syscall with a pointer into the Lisp buffer object.

Lynn



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Blocking calls and threads
  2023-04-20 13:28     ` Po Lu
@ 2023-04-20 14:26       ` Lynn Winebarger
  0 siblings, 0 replies; 11+ messages in thread
From: Lynn Winebarger @ 2023-04-20 14:26 UTC (permalink / raw)
  To: Po Lu; +Cc: Eli Zaretskii, emacs-devel

On Thu, Apr 20, 2023 at 9:28 AM Po Lu <luangruo@yahoo.com> wrote:
> Lynn Winebarger <owinebar@gmail.com> writes:
> > Presumably whatever mechanism is used for the calls you identified
> > below could be generalized.  In practical terms, it would mean
> > assigning locks to every system resource that isn't inherently part of
> > the lisp machine, in this case at least file descriptors.  Then, for
> > example, the read call in emacs_intr_read (in sysdep.c) could be
> > surrounded by a release of the global lock (which yields the thread of
> > the lisp machine) and the re-acquisition of the global lock.  The file
> > descriptor lock might be acquired after yielding the lisp thread, or
> > it might be owned exclusively by the thread that opened it.
>
> I'm afraid that's not so easy.  Parts of Emacs have certainly been
> designed with the assumption that context switching cannot happen inside
> read and friends; at least the Android and NS ports have this problem.

I didn't mean to imply that was *all* that was required - although I
would distinguish concerns around maintaining consistency of the Lisp
machine state (heap/globals) from the correctness of Lisp code that
has race conditions on buffer objects, etc.  I'm not saying the latter
don't have to be addressed, just that they pose distinct engineering
problems from the former.  It's not unlike the move from dynamic to
lexical scope.  Perhaps some day there will be a `thread-safe' local
variable.

> > Are these identified as a group anywhere for reference?  Otherwise, I
> > don't know what is included in the "etc".
>
> Basically anything that calls `thread_select'.  This includes almost
> everything that waits for input.  Please grep around in the C sources.

Thanks,
Lynn



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Blocking calls and threads
  2023-04-20 14:19       ` Lynn Winebarger
@ 2023-04-20 14:36         ` Eli Zaretskii
  2023-04-21  4:39           ` Lynn Winebarger
  0 siblings, 1 reply; 11+ messages in thread
From: Eli Zaretskii @ 2023-04-20 14:36 UTC (permalink / raw)
  To: Lynn Winebarger; +Cc: emacs-devel

> From: Lynn Winebarger <owinebar@gmail.com>
> Date: Thu, 20 Apr 2023 10:19:11 -0400
> Cc: emacs-devel@gnu.org
> 
> > If you yield before issuing the system call, the system call will wait
> > until you re-acquire the lock.  So how will this help?
> 
> You're talking about yielding the system thread, I'm talking about
> yielding the Lisp machine thread.

No, I'm also talking about the Lisp machine thread.  The thread which
calls insert-file-contents and runs the C code of insert-file-contents
and of the subroutines called by insert-file-contents.

> Even though Lisp machine threads are implemented by mapping them to
> the underlying system thread, the Lisp machine execution state is
> kept coherent by the global (interpreter) lock.  Releasing the lock
> is effectively yielding the Lisp machine thread.  The system thread
> will yield implicitly if the read blocks.

What you say here is not relevant to the issue at hand.

> the read operation should either use some temporary buffer and copy
> into the lisp buffer, or wait for data to be ready, then reacquire
> the GIL before invoking the read syscall with a pointer into the
> Lisp buffer object.

Yes, and that's exactly where we will lose: most of the heavy
processing cannot be done in a separate temporary buffer, because it
calls functions from the Lisp machine, and those are written assuming
nothing else is running in the Lisp machine concurrently.  For
example, take the code which decodes the file's contents we have just
read.  I encourage you to take a good look at that code (most of it is
in coding.c) to appreciate the magnitude of the problem.

So the code which can run in parallel with another Lisp thread will be
able to do only very simple jobs, and will also add overhead due to
the need of copying stuff from temporary buffers to Lisp objects.

Of course, we could redesign and reimplement this stuff, but that's a
lot of non-trivial work.  My assumption was that you are considering
relatively lightweight changes on top of the existing code, not a
complete redesign of how these primitives work.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Blocking calls and threads
  2023-04-20 14:36         ` Eli Zaretskii
@ 2023-04-21  4:39           ` Lynn Winebarger
  2023-04-21 13:43             ` Lynn Winebarger
  0 siblings, 1 reply; 11+ messages in thread
From: Lynn Winebarger @ 2023-04-21  4:39 UTC (permalink / raw)
  To: Eli Zaretskii, Stefan Monnier; +Cc: emacs-devel

I'm not sure what the etiquette is here - I keep referring to Stefan's
effort on futur.el, so I've added him explicitly.

On Thu, Apr 20, 2023 at 10:36 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> > From: Lynn Winebarger <owinebar@gmail.com>
> > Date: Thu, 20 Apr 2023 10:19:11 -0400
> > Cc: emacs-devel@gnu.org
> >
> > > If you yield before issuing the system call, the system call will wait
> > > until you re-acquire the lock.  So how will this help?
> >
> > You're talking about yielding the system thread, I'm talking about
> > yielding the Lisp machine thread.
>
> No, I'm also talking about the Lisp machine thread.  The thread which
> calls insert-file-contents and runs the C code of insert-file-contents
> and of the subroutines called by insert-file-contents.

A lisp thread is the context (lisp machine state) observable
(intentionally) by lisp programs.  That is conceptually distinct from
the context tracked by the OS thread.  To paraphrase a great mind, the
identification of the two "is an implementation detail".  Meaning, it
is not normative with respect to the intended semantics of lisp
threads.

> > Even though Lisp machine threads are implemented by mapping them to
> > the underlying system thread, the Lisp machine execution state is
> > kept coherent by the global (interpreter) lock.  Releasing the lock
> > is effectively yielding the Lisp machine thread.  The system thread
> > will yield implicitly if the read blocks.
>
> What you say here is not relevant to the issue at hand.

I don't know what you think is the issue at hand.  My question was
about when (or if) the lisp thread could yield during a blocking I/O
operation.  You appear to have interpreted that question differently
than I intended, so I attempted to be more explicit about what I meant
by "the lisp thread" and "yielding".

> > the read operation should either use some temporary buffer and copy
> > into the lisp buffer, or wait for data to be ready, then reacquire
> > the GIL before invoking the read syscall with a pointer into the
> > Lisp buffer object.
>
> Yes, and that's exactly where we will lose: most of the heavy
> processing cannot be done in a separate temporary buffer, because it
> calls functions from the Lisp machine, and those are written assuming
> nothing else is running in the Lisp machine concurrently.  For
> example, take the code which decodes the file's contents we have just
> read.  I encourage you to take a good look at that code (most of it is
> in coding.c) to appreciate the magnitude of the problem.

I believe you. I did mention that the global lock could be (evidently
*must be*) reacquired before the actual call to "read".  There's also
Tromey's comment on
https://www.reddit.com/r/emacs/comments/utzxir/a_vision_of_a_multithreaded_emacs/.

OTOH, I asked the question in order to understand what it means to
give programmers control over asynchronous execution in controlled
ways.  The most basic kind of control I can think of is whether
functions called in that code are expected to behave synchronously or
asynchronously.  And what is a more basic operation, that could be
done synchronously or asynchronously, than reading text from a file.
If something like insert-file-contents can't be performed
asynchronously (not in parallel, just with other code running while
waiting for IO), the scope of what Stefan's effort is going to be very
limited.  Limited to the point of not being very interesting.

It's also possible that something could be built on the existing data
structures that doesn't rely on more fine-grained locking.  I just
happened to be reading
https://www.gnu.org/software/emacs/manual/html_node/emacs/VCS-Merging.html
today, after seeing this message, and it seemed to me highly relevant
to the problem of concurrent work on a text buffer.  Particularly the
comment "Experience has shown that merging is superior to locking".
Maybe the thing to do to enable asynchronous/concurrent/parallel work
would be to add a new type of buffer, built on the existing one, that
behaves something like a git repo/working copy of the text buffer,
that eventually merges edits, say by windows displaying the buffer
each pulling updates from all the "repos" with checked-out copies.
Then the model for support of asynchronous programming could
encapsulate specifying how to merge and/or handle merge failure.

Maybe that would be too expensive, but at least at first, these
distributed buffers would only be used by programs using explicit
asynchronous programming.  Maybe that approach would even be helpful
in dealing with extremely large files or long lines.  We could call it
"merge-oriented programming". :-)

> So the code which can run in parallel with another Lisp thread will be
> able to do only very simple jobs, and will also add overhead due to
> the need of copying stuff from temporary buffers to Lisp objects.

I'm not talking about running in parallel - there is still just one
lisp machine in this hypothetical.

> Of course, we could redesign and reimplement this stuff, but that's a
> lot of non-trivial work.  My assumption was that you are considering
> relatively lightweight changes on top of the existing code, not a
> complete redesign of how these primitives work.

I wasn't considering anything.  I asked a very limited question for
the purpose of giving some hard thought to the language problem Stefan
requested assistance on.  I didn't offer these elaborations because I
have any plans, only to respond to your question "How could it?".
That is a purely hypothetical question.

Lynn



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Blocking calls and threads
  2023-04-21  4:39           ` Lynn Winebarger
@ 2023-04-21 13:43             ` Lynn Winebarger
  0 siblings, 0 replies; 11+ messages in thread
From: Lynn Winebarger @ 2023-04-21 13:43 UTC (permalink / raw)
  To: Eli Zaretskii, Stefan Monnier; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 6487 bytes --]

On Fri, Apr 21, 2023, 12:39 AM Lynn Winebarger <owinebar@gmail.com> wrote:

> I'm not sure what the etiquette is here - I keep referring to Stefan's
> effort on futur.el, so I've added him explicitly.
>
> On Thu, Apr 20, 2023 at 10:36 AM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > > From: Lynn Winebarger <owinebar@gmail.com>
> > > Date: Thu, 20 Apr 2023 10:19:11 -0400
> > > Cc: emacs-devel@gnu.org
> > >
> > > > If you yield before issuing the system call, the system call will
> wait
> > > > until you re-acquire the lock.  So how will this help?
> > >
> > > You're talking about yielding the system thread, I'm talking about
> > > yielding the Lisp machine thread.
> >
> > No, I'm also talking about the Lisp machine thread.  The thread which
> > calls insert-file-contents and runs the C code of insert-file-contents
> > and of the subroutines called by insert-file-contents.
>
> A lisp thread is the context (lisp machine state) observable
> (intentionally) by lisp programs.  That is conceptually distinct from
> the context tracked by the OS thread.  To paraphrase a great mind, the
> identification of the two "is an implementation detail".  Meaning, it
> is not normative with respect to the intended semantics of lisp
> threads.
>
> > > Even though Lisp machine threads are implemented by mapping them to
> > > the underlying system thread, the Lisp machine execution state is
> > > kept coherent by the global (interpreter) lock.  Releasing the lock
> > > is effectively yielding the Lisp machine thread.  The system thread
> > > will yield implicitly if the read blocks.
> >
> > What you say here is not relevant to the issue at hand.
>
> I don't know what you think is the issue at hand.  My question was
> about when (or if) the lisp thread could yield during a blocking I/O
> operation.  You appear to have interpreted that question differently
> than I intended, so I attempted to be more explicit about what I meant
> by "the lisp thread" and "yielding".
>
> > > the read operation should either use some temporary buffer and copy
> > > into the lisp buffer, or wait for data to be ready, then reacquire
> > > the GIL before invoking the read syscall with a pointer into the
> > > Lisp buffer object.
> >
> > Yes, and that's exactly where we will lose: most of the heavy
> > processing cannot be done in a separate temporary buffer, because it
> > calls functions from the Lisp machine, and those are written assuming
> > nothing else is running in the Lisp machine concurrently.  For
> > example, take the code which decodes the file's contents we have just
> > read.  I encourage you to take a good look at that code (most of it is
> > in coding.c) to appreciate the magnitude of the problem.
>
> I believe you. I did mention that the global lock could be (evidently
> *must be*) reacquired before the actual call to "read".  There's also
> Tromey's comment on
>
> https://www.reddit.com/r/emacs/comments/utzxir/a_vision_of_a_multithreaded_emacs/
> .
>
> OTOH, I asked the question in order to understand what it means to
> give programmers control over asynchronous execution in controlled
> ways.  The most basic kind of control I can think of is whether
> functions called in that code are expected to behave synchronously or
> asynchronously.  And what is a more basic operation, that could be
> done synchronously or asynchronously, than reading text from a file.
> If something like insert-file-contents can't be performed
> asynchronously (not in parallel, just with other code running while
> waiting for IO), the scope of what Stefan's effort is going to be very
> limited.  Limited to the point of not being very interesting.
>
> It's also possible that something could be built on the existing data
> structures that doesn't rely on more fine-grained locking.  I just
> happened to be reading
> https://www.gnu.org/software/emacs/manual/html_node/emacs/VCS-Merging.html
> today, after seeing this message, and it seemed to me highly relevant
> to the problem of concurrent work on a text buffer.  Particularly the
> comment "Experience has shown that merging is superior to locking".
> Maybe the thing to do to enable asynchronous/concurrent/parallel work
> would be to add a new type of buffer, built on the existing one, that
> behaves something like a git repo/working copy of the text buffer,
> that eventually merges edits, say by windows displaying the buffer
> each pulling updates from all the "repos" with checked-out copies.
> Then the model for support of asynchronous programming could
> encapsulate specifying how to merge and/or handle merge failure.
>
> Maybe that would be too expensive, but at least at first, these
> distributed buffers would only be used by programs using explicit
> asynchronous programming.  Maybe that approach would even be helpful
> in dealing with extremely large files or long lines.  We could call it
> "merge-oriented programming". :-)
>

I forgot to mention the concurrent version of the buffer would need a
functional representation to avoid copying during the merge.  Something
along the lines of Okasaki's purely functional strings, except including
all the other components of buffers - overlays, local variables, and
whatever else would be implicated.  I don't know if this would require a
complete reimplementation of buffers, or if the current implementation
could be tweaked to serve as an underlying component of a zippered buffer.




> > So the code which can run in parallel with another Lisp thread will be
> > able to do only very simple jobs, and will also add overhead due to
> > the need of copying stuff from temporary buffers to Lisp objects.
>
> I'm not talking about running in parallel - there is still just one
> lisp machine in this hypothetical.
>
> > Of course, we could redesign and reimplement this stuff, but that's a
> > lot of non-trivial work.  My assumption was that you are considering
> > relatively lightweight changes on top of the existing code, not a
> > complete redesign of how these primitives work.
>
> I wasn't considering anything.  I asked a very limited question for
> the purpose of giving some hard thought to the language problem Stefan
> requested assistance on.  I didn't offer these elaborations because I
> have any plans, only to respond to your question "How could it?".
> That is a purely hypothetical question.
>
> Lynn
>

[-- Attachment #2: Type: text/html, Size: 8205 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2023-04-21 13:43 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-04-20  5:31 Blocking calls and threads Lynn Winebarger
2023-04-20  7:00 ` Po Lu
2023-04-20  7:23 ` Eli Zaretskii
2023-04-20 13:06   ` Lynn Winebarger
2023-04-20 13:28     ` Po Lu
2023-04-20 14:26       ` Lynn Winebarger
2023-04-20 13:37     ` Eli Zaretskii
2023-04-20 14:19       ` Lynn Winebarger
2023-04-20 14:36         ` Eli Zaretskii
2023-04-21  4:39           ` Lynn Winebarger
2023-04-21 13:43             ` Lynn Winebarger

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).