unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Questions about throw-on-input
@ 2020-05-07  7:31 Ivan Yonchovski
  2020-05-07 12:36 ` Eli Zaretskii
  2020-05-07 13:49 ` Stefan Monnier
  0 siblings, 2 replies; 52+ messages in thread
From: Ivan Yonchovski @ 2020-05-07  7:31 UTC (permalink / raw)
  To: emacs-devel


Hi all,

I have few questions regarding throw-on-input:

1. In the following example:

(dotimes (_ 10)
  (message "Length %s"
           (length
            (let (result)
              (catch t
                (let ((throw-on-input t))
                  (dotimes (counter 10000000)
                    (push (number-to-string counter) result))))
              result))))

.. after I execute the following block each of the 10 computations will be
canceled after pressing C-n for example, how do I force the handling of
the command to be processed? I tried redisplay but it does not help.

2. Consider the following pieces of code:

(message "Length %s"
         (length
          (let (result)
            (catch t
              (let ((throw-on-input t))
                (dotimes (counter 10000000)
                  (push (number-to-string counter) result))))
            result)))


(run-with-idle-timer
 0.0
 nil
 (lambda ()
   (message "Length %s"
            (length
             (let (result)
               (catch t
                 (let ((throw-on-input t))
                   (dotimes (counter 10000000)
                     (push (number-to-string counter) result))))
               result)))))

The issue is with the second block, it seems like throw-on-input is
disregarded when used in run-with-idle-timer. Can anyone confirm if this
is a bug/desired behavior or I should use something else if I want to
run cancelable tasks in on-idle?

Thanks,
Ivan



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

* Re: Questions about throw-on-input
  2020-05-07  7:31 Ivan Yonchovski
@ 2020-05-07 12:36 ` Eli Zaretskii
  2020-05-07 14:28   ` Ivan Yonchovski
  2020-05-07 21:11   ` yyoncho
  2020-05-07 13:49 ` Stefan Monnier
  1 sibling, 2 replies; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-07 12:36 UTC (permalink / raw)
  To: Ivan Yonchovski; +Cc: emacs-devel

> From: Ivan Yonchovski <yyoncho@gmail.com>
> Date: Thu, 07 May 2020 10:31:23 +0300
> 
> 
> 1. In the following example:
> 
> (dotimes (_ 10)
>   (message "Length %s"
>            (length
>             (let (result)
>               (catch t
>                 (let ((throw-on-input t))
>                   (dotimes (counter 10000000)
>                     (push (number-to-string counter) result))))
>               result))))
> 
> .. after I execute the following block each of the 10 computations will be
> canceled after pressing C-n for example, how do I force the handling of
> the command to be processed? I tried redisplay but it does not help.

Invoking redisplay won't help because the commands which interrupted
the inner loop (C-n) were not yet executed.  Emacs will process them
only after the outer loop ends, because that outer loop is the last
command, and it is still being executed.  Emacs doesn't perform
commands in the middle of another command.

> (message "Length %s"
>          (length
>           (let (result)
>             (catch t
>               (let ((throw-on-input t))
>                 (dotimes (counter 10000000)
>                   (push (number-to-string counter) result))))
>             result)))
> 
> 
> (run-with-idle-timer
>  0.0
>  nil
>  (lambda ()
>    (message "Length %s"
>             (length
>              (let (result)
>                (catch t
>                  (let ((throw-on-input t))
>                    (dotimes (counter 10000000)
>                      (push (number-to-string counter) result))))
>                result)))))
> 
> The issue is with the second block, it seems like throw-on-input is
> disregarded when used in run-with-idle-timer. Can anyone confirm if this
> is a bug/desired behavior or I should use something else if I want to
> run cancelable tasks in on-idle?

When the time function is run, Emacs binds inhibit-quit to t (so that
the user's C-g would not interrupt the timer function, for example).
And throw-on-input uses quitting to do its job.

Why do you need to interrupt an idle timer like that?  The usual way
of doing this is not to call expensive functions in an idle timer, and
if you have a lot of processing, divide them into small enough chunks
and do it piecemeal.  That's what jit-stealth font-lock does, for
example.



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

* Re: Questions about throw-on-input
  2020-05-07  7:31 Ivan Yonchovski
  2020-05-07 12:36 ` Eli Zaretskii
@ 2020-05-07 13:49 ` Stefan Monnier
  2020-05-07 15:36   ` Ivan Yonchovski
  1 sibling, 1 reply; 52+ messages in thread
From: Stefan Monnier @ 2020-05-07 13:49 UTC (permalink / raw)
  To: Ivan Yonchovski; +Cc: emacs-devel

>                 (let ((throw-on-input t))

Why do you do that instead of using `while-no-input`?

> .. after I execute the following block each of the 10 computations will be
> canceled after pressing C-n for example, how do I force the handling of
> the command to be processed?

You mean the event is "eaten"?  I must say I'm not sure why.

> The issue is with the second block, it seems like throw-on-input is
> disregarded when used in run-with-idle-timer.

That's because timers are run with `inhibit-quit` which interferes.
`while-no-input` would take care of that.


        Stefan




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

* Re: Questions about throw-on-input
  2020-05-07 12:36 ` Eli Zaretskii
@ 2020-05-07 14:28   ` Ivan Yonchovski
  2020-05-07 21:11   ` yyoncho
  1 sibling, 0 replies; 52+ messages in thread
From: Ivan Yonchovski @ 2020-05-07 14:28 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel


Hi Eli,

Thank you, this solved my issue.

> Why do you need to interrupt an idle timer like that?  The usual way
> of doing this is not to call expensive functions in an idle timer, and
> if you have a lot of processing, divide them into small enough chunks
> and do it piecemeal.  That's what jit-stealth font-lock does, for
> example.

I am playing with the idea for a function which will be able stop right
after there is user input and it will continue from where it has been
stopped preserving as much from what already has processed/calculated.

Thanks,
Ivan



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

* Re: Questions about throw-on-input
  2020-05-07 13:49 ` Stefan Monnier
@ 2020-05-07 15:36   ` Ivan Yonchovski
  0 siblings, 0 replies; 52+ messages in thread
From: Ivan Yonchovski @ 2020-05-07 15:36 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Hi Stefan,

Thank you for the reply.

>
> Why do you do that instead of using `while-no-input`?
>

No particular reason. I think that it the end I will end up with
`while-no-input`.

> You mean the event is "eaten"?  I must say I'm not sure why.

I got the answer from Eli.

>
> That's because timers are run with `inhibit-quit` which interferes.
> `while-no-input` would take care of that.
>

Yes, I didn't know that.


Thanks,
Ivan



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

* Re: Questions about throw-on-input
  2020-05-07 12:36 ` Eli Zaretskii
  2020-05-07 14:28   ` Ivan Yonchovski
@ 2020-05-07 21:11   ` yyoncho
  2020-05-08  1:58     ` Stefan Monnier
  2020-05-08 10:41     ` Eli Zaretskii
  1 sibling, 2 replies; 52+ messages in thread
From: yyoncho @ 2020-05-07 21:11 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

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

Hi Eli,

Out of curiosity, do you think that having a function
(process-events) which will process all keyboard(?) events
and resume the current invocation can be implemented easily?
AFAIK a lot of gui toolkits have that kind of function, e. g.
https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.application.doevents?view=netcore-3.1

IMO it will be very useful for certain cases.

Thanks,
Ivan

On Thu, May 7, 2020 at 3:37 PM Eli Zaretskii <eliz@gnu.org> wrote:

> > From: Ivan Yonchovski <yyoncho@gmail.com>
> > Date: Thu, 07 May 2020 10:31:23 +0300
> >
> >
> > 1. In the following example:
> >
> > (dotimes (_ 10)
> >   (message "Length %s"
> >            (length
> >             (let (result)
> >               (catch t
> >                 (let ((throw-on-input t))
> >                   (dotimes (counter 10000000)
> >                     (push (number-to-string counter) result))))
> >               result))))
> >
> > .. after I execute the following block each of the 10 computations will
> be
> > canceled after pressing C-n for example, how do I force the handling of
> > the command to be processed? I tried redisplay but it does not help.
>
> Invoking redisplay won't help because the commands which interrupted
> the inner loop (C-n) were not yet executed.  Emacs will process them
> only after the outer loop ends, because that outer loop is the last
> command, and it is still being executed.  Emacs doesn't perform
> commands in the middle of another command.
>
> > (message "Length %s"
> >          (length
> >           (let (result)
> >             (catch t
> >               (let ((throw-on-input t))
> >                 (dotimes (counter 10000000)
> >                   (push (number-to-string counter) result))))
> >             result)))
> >
> >
> > (run-with-idle-timer
> >  0.0
> >  nil
> >  (lambda ()
> >    (message "Length %s"
> >             (length
> >              (let (result)
> >                (catch t
> >                  (let ((throw-on-input t))
> >                    (dotimes (counter 10000000)
> >                      (push (number-to-string counter) result))))
> >                result)))))
> >
> > The issue is with the second block, it seems like throw-on-input is
> > disregarded when used in run-with-idle-timer. Can anyone confirm if this
> > is a bug/desired behavior or I should use something else if I want to
> > run cancelable tasks in on-idle?
>
> When the time function is run, Emacs binds inhibit-quit to t (so that
> the user's C-g would not interrupt the timer function, for example).
> And throw-on-input uses quitting to do its job.
>
> Why do you need to interrupt an idle timer like that?  The usual way
> of doing this is not to call expensive functions in an idle timer, and
> if you have a lot of processing, divide them into small enough chunks
> and do it piecemeal.  That's what jit-stealth font-lock does, for
> example.
>

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

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

* Re: Questions about throw-on-input
  2020-05-07 21:11   ` yyoncho
@ 2020-05-08  1:58     ` Stefan Monnier
  2020-05-08  4:36       ` yyoncho
  2020-05-12  4:15       ` Michael Heerdegen
  2020-05-08 10:41     ` Eli Zaretskii
  1 sibling, 2 replies; 52+ messages in thread
From: Stefan Monnier @ 2020-05-08  1:58 UTC (permalink / raw)
  To: yyoncho; +Cc: Eli Zaretskii, emacs-devel

> Out of curiosity, do you think that having a function
> (process-events) which will process all keyboard(?) events
> and resume the current invocation can be implemented easily?

It can be implemented, but it won't have the desired semantics.
If you want something robust you have 2 options:

- write in an event-driven style (or CPS style) so that you can easily
  stop at various points in the program and stash the rest of the
  computation for later.

- use a thread (which will basically do the same, but transparently,
  i.e. without the awkward programming style.)


        Stefan


> AFAIK a lot of gui toolkits have that kind of function, e. g.
> https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.application.doevents?view=netcore-3.1
>
> IMO it will be very useful for certain cases.
>
> Thanks,
> Ivan
>
> On Thu, May 7, 2020 at 3:37 PM Eli Zaretskii <eliz@gnu.org> wrote:
>
>> > From: Ivan Yonchovski <yyoncho@gmail.com>
>> > Date: Thu, 07 May 2020 10:31:23 +0300
>> >
>> >
>> > 1. In the following example:
>> >
>> > (dotimes (_ 10)
>> >   (message "Length %s"
>> >            (length
>> >             (let (result)
>> >               (catch t
>> >                 (let ((throw-on-input t))
>> >                   (dotimes (counter 10000000)
>> >                     (push (number-to-string counter) result))))
>> >               result))))
>> >
>> > .. after I execute the following block each of the 10 computations will
>> be
>> > canceled after pressing C-n for example, how do I force the handling of
>> > the command to be processed? I tried redisplay but it does not help.
>>
>> Invoking redisplay won't help because the commands which interrupted
>> the inner loop (C-n) were not yet executed.  Emacs will process them
>> only after the outer loop ends, because that outer loop is the last
>> command, and it is still being executed.  Emacs doesn't perform
>> commands in the middle of another command.
>>
>> > (message "Length %s"
>> >          (length
>> >           (let (result)
>> >             (catch t
>> >               (let ((throw-on-input t))
>> >                 (dotimes (counter 10000000)
>> >                   (push (number-to-string counter) result))))
>> >             result)))
>> >
>> >
>> > (run-with-idle-timer
>> >  0.0
>> >  nil
>> >  (lambda ()
>> >    (message "Length %s"
>> >             (length
>> >              (let (result)
>> >                (catch t
>> >                  (let ((throw-on-input t))
>> >                    (dotimes (counter 10000000)
>> >                      (push (number-to-string counter) result))))
>> >                result)))))
>> >
>> > The issue is with the second block, it seems like throw-on-input is
>> > disregarded when used in run-with-idle-timer. Can anyone confirm if this
>> > is a bug/desired behavior or I should use something else if I want to
>> > run cancelable tasks in on-idle?
>>
>> When the time function is run, Emacs binds inhibit-quit to t (so that
>> the user's C-g would not interrupt the timer function, for example).
>> And throw-on-input uses quitting to do its job.
>>
>> Why do you need to interrupt an idle timer like that?  The usual way
>> of doing this is not to call expensive functions in an idle timer, and
>> if you have a lot of processing, divide them into small enough chunks
>> and do it piecemeal.  That's what jit-stealth font-lock does, for
>> example.
>>




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

* Re: Questions about throw-on-input
  2020-05-08  1:58     ` Stefan Monnier
@ 2020-05-08  4:36       ` yyoncho
  2020-05-08  4:43         ` yyoncho
  2020-05-12  4:15       ` Michael Heerdegen
  1 sibling, 1 reply; 52+ messages in thread
From: yyoncho @ 2020-05-08  4:36 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, emacs-devel

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

Hi Stefan,

Thank you for your reply! Can you elaborate on "won't have the desired
semantics"? I would suggest something crazier - using inhibit-quit to

Thanks,
Ivan

On Fri, May 8, 2020 at 4:59 AM Stefan Monnier <monnier@iro.umontreal.ca>
wrote:

> > Out of curiosity, do you think that having a function
> > (process-events) which will process all keyboard(?) events
> > and resume the current invocation can be implemented easily?
>
> It can be implemented, but it won't have the desired semantics.
> If you want something robust you have 2 options:
>
> - write in an event-driven style (or CPS style) so that you can easily
>   stop at various points in the program and stash the rest of the
>   computation for later.
>
> - use a thread (which will basically do the same, but transparently,
>   i.e. without the awkward programming style.)
>
>
>         Stefan
>
>
> > AFAIK a lot of gui toolkits have that kind of function, e. g.
> >
> https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.application.doevents?view=netcore-3.1
> >
> > IMO it will be very useful for certain cases.
> >
> > Thanks,
> > Ivan
> >
> > On Thu, May 7, 2020 at 3:37 PM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> >> > From: Ivan Yonchovski <yyoncho@gmail.com>
> >> > Date: Thu, 07 May 2020 10:31:23 +0300
> >> >
> >> >
> >> > 1. In the following example:
> >> >
> >> > (dotimes (_ 10)
> >> >   (message "Length %s"
> >> >            (length
> >> >             (let (result)
> >> >               (catch t
> >> >                 (let ((throw-on-input t))
> >> >                   (dotimes (counter 10000000)
> >> >                     (push (number-to-string counter) result))))
> >> >               result))))
> >> >
> >> > .. after I execute the following block each of the 10 computations
> will
> >> be
> >> > canceled after pressing C-n for example, how do I force the handling
> of
> >> > the command to be processed? I tried redisplay but it does not help.
> >>
> >> Invoking redisplay won't help because the commands which interrupted
> >> the inner loop (C-n) were not yet executed.  Emacs will process them
> >> only after the outer loop ends, because that outer loop is the last
> >> command, and it is still being executed.  Emacs doesn't perform
> >> commands in the middle of another command.
> >>
> >> > (message "Length %s"
> >> >          (length
> >> >           (let (result)
> >> >             (catch t
> >> >               (let ((throw-on-input t))
> >> >                 (dotimes (counter 10000000)
> >> >                   (push (number-to-string counter) result))))
> >> >             result)))
> >> >
> >> >
> >> > (run-with-idle-timer
> >> >  0.0
> >> >  nil
> >> >  (lambda ()
> >> >    (message "Length %s"
> >> >             (length
> >> >              (let (result)
> >> >                (catch t
> >> >                  (let ((throw-on-input t))
> >> >                    (dotimes (counter 10000000)
> >> >                      (push (number-to-string counter) result))))
> >> >                result)))))
> >> >
> >> > The issue is with the second block, it seems like throw-on-input is
> >> > disregarded when used in run-with-idle-timer. Can anyone confirm if
> this
> >> > is a bug/desired behavior or I should use something else if I want to
> >> > run cancelable tasks in on-idle?
> >>
> >> When the time function is run, Emacs binds inhibit-quit to t (so that
> >> the user's C-g would not interrupt the timer function, for example).
> >> And throw-on-input uses quitting to do its job.
> >>
> >> Why do you need to interrupt an idle timer like that?  The usual way
> >> of doing this is not to call expensive functions in an idle timer, and
> >> if you have a lot of processing, divide them into small enough chunks
> >> and do it piecemeal.  That's what jit-stealth font-lock does, for
> >> example.
> >>
>
>

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

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

* Re: Questions about throw-on-input
  2020-05-08  4:36       ` yyoncho
@ 2020-05-08  4:43         ` yyoncho
  0 siblings, 0 replies; 52+ messages in thread
From: yyoncho @ 2020-05-08  4:43 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, emacs-devel

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

Sorry, I accidentally pressed send before finishing my reply.

I was about to suggest using the quit-flag to indicate - "instead
of quitting process events during the execution of the block", like that

(let ((quit-flag :process-events))
  (slow-operation))

Not sure if this will work but in case it works, it will be great!

Thanks,
Ivan

On Fri, May 8, 2020 at 7:36 AM yyoncho <yyoncho@gmail.com> wrote:

> Hi Stefan,
>
> Thank you for your reply! Can you elaborate on "won't have the desired
> semantics"? I would suggest something crazier - using inhibit-quit to
>
> Thanks,
> Ivan
>
> On Fri, May 8, 2020 at 4:59 AM Stefan Monnier <monnier@iro.umontreal.ca>
> wrote:
>
>> > Out of curiosity, do you think that having a function
>> > (process-events) which will process all keyboard(?) events
>> > and resume the current invocation can be implemented easily?
>>
>> It can be implemented, but it won't have the desired semantics.
>> If you want something robust you have 2 options:
>>
>> - write in an event-driven style (or CPS style) so that you can easily
>>   stop at various points in the program and stash the rest of the
>>   computation for later.
>>
>> - use a thread (which will basically do the same, but transparently,
>>   i.e. without the awkward programming style.)
>>
>>
>>         Stefan
>>
>>
>> > AFAIK a lot of gui toolkits have that kind of function, e. g.
>> >
>> https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.application.doevents?view=netcore-3.1
>> >
>> > IMO it will be very useful for certain cases.
>> >
>> > Thanks,
>> > Ivan
>> >
>> > On Thu, May 7, 2020 at 3:37 PM Eli Zaretskii <eliz@gnu.org> wrote:
>> >
>> >> > From: Ivan Yonchovski <yyoncho@gmail.com>
>> >> > Date: Thu, 07 May 2020 10:31:23 +0300
>> >> >
>> >> >
>> >> > 1. In the following example:
>> >> >
>> >> > (dotimes (_ 10)
>> >> >   (message "Length %s"
>> >> >            (length
>> >> >             (let (result)
>> >> >               (catch t
>> >> >                 (let ((throw-on-input t))
>> >> >                   (dotimes (counter 10000000)
>> >> >                     (push (number-to-string counter) result))))
>> >> >               result))))
>> >> >
>> >> > .. after I execute the following block each of the 10 computations
>> will
>> >> be
>> >> > canceled after pressing C-n for example, how do I force the handling
>> of
>> >> > the command to be processed? I tried redisplay but it does not help.
>> >>
>> >> Invoking redisplay won't help because the commands which interrupted
>> >> the inner loop (C-n) were not yet executed.  Emacs will process them
>> >> only after the outer loop ends, because that outer loop is the last
>> >> command, and it is still being executed.  Emacs doesn't perform
>> >> commands in the middle of another command.
>> >>
>> >> > (message "Length %s"
>> >> >          (length
>> >> >           (let (result)
>> >> >             (catch t
>> >> >               (let ((throw-on-input t))
>> >> >                 (dotimes (counter 10000000)
>> >> >                   (push (number-to-string counter) result))))
>> >> >             result)))
>> >> >
>> >> >
>> >> > (run-with-idle-timer
>> >> >  0.0
>> >> >  nil
>> >> >  (lambda ()
>> >> >    (message "Length %s"
>> >> >             (length
>> >> >              (let (result)
>> >> >                (catch t
>> >> >                  (let ((throw-on-input t))
>> >> >                    (dotimes (counter 10000000)
>> >> >                      (push (number-to-string counter) result))))
>> >> >                result)))))
>> >> >
>> >> > The issue is with the second block, it seems like throw-on-input is
>> >> > disregarded when used in run-with-idle-timer. Can anyone confirm if
>> this
>> >> > is a bug/desired behavior or I should use something else if I want to
>> >> > run cancelable tasks in on-idle?
>> >>
>> >> When the time function is run, Emacs binds inhibit-quit to t (so that
>> >> the user's C-g would not interrupt the timer function, for example).
>> >> And throw-on-input uses quitting to do its job.
>> >>
>> >> Why do you need to interrupt an idle timer like that?  The usual way
>> >> of doing this is not to call expensive functions in an idle timer, and
>> >> if you have a lot of processing, divide them into small enough chunks
>> >> and do it piecemeal.  That's what jit-stealth font-lock does, for
>> >> example.
>> >>
>>
>>

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

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

* Re: Questions about throw-on-input
  2020-05-07 21:11   ` yyoncho
  2020-05-08  1:58     ` Stefan Monnier
@ 2020-05-08 10:41     ` Eli Zaretskii
  2020-05-08 11:23       ` Ivan Yonchovski
  1 sibling, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-08 10:41 UTC (permalink / raw)
  To: yyoncho; +Cc: emacs-devel

> From: yyoncho <yyoncho@gmail.com>
> Date: Fri, 8 May 2020 00:11:26 +0300
> Cc: emacs-devel <emacs-devel@gnu.org>
> 
> Out of curiosity, do you think that having a function 
> (process-events) which will process all keyboard(?) events
> and resume the current invocation can be implemented easily? 

By "processing all keyboard events" do you mean invoking the commands
those events are bound to?  If so, I don't think we have machinery to
do that in Emacs: there's too much of global state that would get in
the way.

> AFAIK a lot of gui toolkits have that kind of function, e. g. 
> https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.application.doevents?view=netcore-3.1 
> IMO it will be very useful for certain cases.

AFAIU, such facilities need to have a separate event loop that
generally runs in a separate thread.



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

* Re: Questions about throw-on-input
  2020-05-08 10:41     ` Eli Zaretskii
@ 2020-05-08 11:23       ` Ivan Yonchovski
  2020-05-08 11:45         ` Eli Zaretskii
  2020-05-08 14:55         ` Stefan Monnier
  0 siblings, 2 replies; 52+ messages in thread
From: Ivan Yonchovski @ 2020-05-08 11:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

Hi Eli,

> By "processing all keyboard events" do you mean invoking the commands
> those events are bound to?

Yes.

> If so, I don't think we have machinery to do that in Emacs: there's
> too much of global state that would get in the way.

Here it is overly simplistic code that is close to what I am trying to
achieve.

(defun process-events ()
  (when (input-pending-p)
    (run-with-timer 0.01 nil (lambda () (throw 'exit nil)))
    (recursive-edit)))

(dotimes (counter 1000)
  (sleep-for 0.01) ;; simulate execution of N tasks
  (message "%s" counter)
  (process-events))

This code is able to handle C-n but obviously it will break if someone
starts another recursive-edit or for complex keybindings, e. g. `C-x b`.
Are you aware of something doing something similar? Do you think it
makes sense if you want to process something slow on the background
without blocking emacs?

> AFAIU, such facilities need to have a separate event loop that
> generally runs in a separate thread.

In the C# case it all happens on the UI thread. DoEvents means handle
mouse clicks, repaint controls, etc(the stuff from the event loop) and
then continue with current execution.

Thanks,
Ivan



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

* Re: Questions about throw-on-input
  2020-05-08 11:23       ` Ivan Yonchovski
@ 2020-05-08 11:45         ` Eli Zaretskii
  2020-05-08 11:55           ` yyoncho
  2020-05-08 14:55         ` Stefan Monnier
  1 sibling, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-08 11:45 UTC (permalink / raw)
  To: Ivan Yonchovski; +Cc: emacs-devel

> From: Ivan Yonchovski <yyoncho@gmail.com>
> Cc: emacs-devel@gnu.org
> Date: Fri, 08 May 2020 14:23:34 +0300
> 
> (defun process-events ()
>   (when (input-pending-p)
>     (run-with-timer 0.01 nil (lambda () (throw 'exit nil)))
>     (recursive-edit)))
> 
> (dotimes (counter 1000)
>   (sleep-for 0.01) ;; simulate execution of N tasks
>   (message "%s" counter)
>   (process-events))
> 
> This code is able to handle C-n but obviously it will break if someone
> starts another recursive-edit or for complex keybindings, e. g. `C-x b`.

I think you will indeed find that this is very fragile.

> Are you aware of something doing something similar? Do you think it
> makes sense if you want to process something slow on the background
> without blocking emacs?

I think this is why we added threads to Emacs.  Why not try doing this
in a thread?

> > AFAIU, such facilities need to have a separate event loop that
> > generally runs in a separate thread.
> 
> In the C# case it all happens on the UI thread. DoEvents means handle
> mouse clicks, repaint controls, etc(the stuff from the event loop) and
> then continue with current execution.

When display is as intimately connected to the global state as it is
in Emacs, I don't think such separation can fly.



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

* Re: Questions about throw-on-input
  2020-05-08 11:45         ` Eli Zaretskii
@ 2020-05-08 11:55           ` yyoncho
  0 siblings, 0 replies; 52+ messages in thread
From: yyoncho @ 2020-05-08 11:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

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

Hi Eli,

Threads seem to the correct solution for the problem I am trying to solve.
Thank you for your help.

Thanks,
Ivan

On Fri, May 8, 2020 at 2:45 PM Eli Zaretskii <eliz@gnu.org> wrote:

> > From: Ivan Yonchovski <yyoncho@gmail.com>
> > Cc: emacs-devel@gnu.org
> > Date: Fri, 08 May 2020 14:23:34 +0300
> >
> > (defun process-events ()
> >   (when (input-pending-p)
> >     (run-with-timer 0.01 nil (lambda () (throw 'exit nil)))
> >     (recursive-edit)))
> >
> > (dotimes (counter 1000)
> >   (sleep-for 0.01) ;; simulate execution of N tasks
> >   (message "%s" counter)
> >   (process-events))
> >
> > This code is able to handle C-n but obviously it will break if someone
> > starts another recursive-edit or for complex keybindings, e. g. `C-x b`.
>
> I think you will indeed find that this is very fragile.
>
> > Are you aware of something doing something similar? Do you think it
> > makes sense if you want to process something slow on the background
> > without blocking emacs?
>
> I think this is why we added threads to Emacs.  Why not try doing this
> in a thread?
>
> > > AFAIU, such facilities need to have a separate event loop that
> > > generally runs in a separate thread.
> >
> > In the C# case it all happens on the UI thread. DoEvents means handle
> > mouse clicks, repaint controls, etc(the stuff from the event loop) and
> > then continue with current execution.
>
> When display is as intimately connected to the global state as it is
> in Emacs, I don't think such separation can fly.
>

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

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

* Re: Questions about throw-on-input
  2020-05-08 11:23       ` Ivan Yonchovski
  2020-05-08 11:45         ` Eli Zaretskii
@ 2020-05-08 14:55         ` Stefan Monnier
  2020-05-08 18:04           ` yyoncho
  1 sibling, 1 reply; 52+ messages in thread
From: Stefan Monnier @ 2020-05-08 14:55 UTC (permalink / raw)
  To: Ivan Yonchovski; +Cc: Eli Zaretskii, emacs-devel

> Can you elaborate on "won't have the desired semantics"?
[...]

> Here it is overly simplistic code that is close to what I am trying to
> achieve.
[...]
> This code is able to handle C-n but obviously it will break if someone
> starts another recursive-edit or for complex keybindings, e. g. `C-x b`.

I see you've found an example of "not the desired semantics".
There will be many others, most of which I can't even foresee.

BTW, maybe when Emacs is built with support for threads, timers should
be run in a separate thread (so you could just call `thread-yield` to
do what you want).


        Stefan




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

* Re: Questions about throw-on-input
  2020-05-08 14:55         ` Stefan Monnier
@ 2020-05-08 18:04           ` yyoncho
  0 siblings, 0 replies; 52+ messages in thread
From: yyoncho @ 2020-05-08 18:04 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, emacs-devel

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

> BTW, maybe when Emacs is built with support for threads, timers should
> be run in a separate thread (so you could just call `thread-yield` to
> do what you want).
>

Yes, this is what I was actually looking for.

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

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

* Re: Questions about throw-on-input
@ 2020-05-09 13:09 Alexander Miller
  2020-05-10 11:11 ` yyoncho
  0 siblings, 1 reply; 52+ messages in thread
From: Alexander Miller @ 2020-05-09 13:09 UTC (permalink / raw)
  To: yyoncho; +Cc: emacs-devel

[I had to copy the In-Reply-To header from the page source because the
reply-to button
wouldn't set it, so let's hope I'm doing this right.]

Incidentally I have recently been playing around with a similar idea -
to use a worker thread
to split and run long tasks in the background. Here's what I came up
with so far:

(defconst worker-mutex (make-mutex "*WORKER MUTEX*"))
(defconst worker-cond-var (make-condition-variable worker-mutex))
(defvar worker-queue (list))

(setf
  worker
  (make-thread
   (lambda ()
     (while t
       (while worker-queue
         (let* ((work-unit (pop worker-queue))
                (fn (car work-unit))
                (args (cdr work-unit)))
           (apply fn args)
           (thread-yield)))
       (with-mutex worker-mutex
         (condition-wait worker-cond-var))))
   "*WORKER*"))

(setf worker-timer
       (run-with-idle-timer
        1 t (lambda ()
              (when worker-queue
                (with-mutex worker-mutex
                  (condition-notify worker-cond-var))))))

(push (list #'shell-command-to-string "notify-send 'Hello' 'World!'")
worker-queue)
(push (list #'message "Hello %s!" "World") worker-queue)
(push (list #'call-interactively #'treemacs) worker-queue)

Get enough thread-yield or input-pending checks into the work the thread
is doing and
you might just be able to get around blocking the UI despite having
plenty to do.






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

* Re: Questions about throw-on-input
  2020-05-09 13:09 Questions about throw-on-input Alexander Miller
@ 2020-05-10 11:11 ` yyoncho
  0 siblings, 0 replies; 52+ messages in thread
From: yyoncho @ 2020-05-10 11:11 UTC (permalink / raw)
  To: Alexander Miller; +Cc: emacs-devel

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

Thank you, Alexander.

I was planning to span a new thread but the approach with the queue might
be a better fit for us. Do you have the numbers for what will yield better
performance - checking input-pending and then thread-yield or directly
calling thread-yield?

Ivan

On Sat, May 9, 2020 at 4:09 PM Alexander Miller <alexanderm@web.de> wrote:

> [I had to copy the In-Reply-To header from the page source because the
> reply-to button
> wouldn't set it, so let's hope I'm doing this right.]
>
> Incidentally I have recently been playing around with a similar idea -
> to use a worker thread
> to split and run long tasks in the background. Here's what I came up
> with so far:
>
> (defconst worker-mutex (make-mutex "*WORKER MUTEX*"))
> (defconst worker-cond-var (make-condition-variable worker-mutex))
> (defvar worker-queue (list))
>
> (setf
>   worker
>   (make-thread
>    (lambda ()
>      (while t
>        (while worker-queue
>          (let* ((work-unit (pop worker-queue))
>                 (fn (car work-unit))
>                 (args (cdr work-unit)))
>            (apply fn args)
>            (thread-yield)))
>        (with-mutex worker-mutex
>          (condition-wait worker-cond-var))))
>    "*WORKER*"))
>
> (setf worker-timer
>        (run-with-idle-timer
>         1 t (lambda ()
>               (when worker-queue
>                 (with-mutex worker-mutex
>                   (condition-notify worker-cond-var))))))
>
> (push (list #'shell-command-to-string "notify-send 'Hello' 'World!'")
> worker-queue)
> (push (list #'message "Hello %s!" "World") worker-queue)
> (push (list #'call-interactively #'treemacs) worker-queue)
>
> Get enough thread-yield or input-pending checks into the work the thread
> is doing and
> you might just be able to get around blocking the UI despite having
> plenty to do.
>
>
>
>

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

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

* Re: Questions about throw-on-input
@ 2020-05-10 13:47 Alexander Miller
  2020-05-11 14:13 ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Alexander Miller @ 2020-05-10 13:47 UTC (permalink / raw)
  To: yyoncho; +Cc: emacs-devel

I have built a simple benchmark now, and it looks like neither version
is any good.

Checking (input-pending-p) does not work in this scenario. When your
worker thread is actually busy (simulated by the 10000 calls to random
below) input-pending-p will not return t, no matter how much you hammer
the keyboard in the meatime. The yield-time message will not appear even
once. So it looks like keeping the CPU busy also prevents the processing
of input events.

The always yielding approach does not work either. All it does is give
you some extremely small windows, measured in ms at best, to make your
input, but most of the time it will be ignored anyway because of the
problem described above.

The only way I was able to get this to run smoothly was to replace the
yield with an uncoditional (sleep-for 0.00001). That allowed my input to
be processed without perceptible delay and even the performance impact
seemed to be acceptable: when compiled it increased the benchmark's
runtime from ~5 seconds to ~5.3 seconds.

So whatever you are up to, it looks like power-napping is the way to go.

Here is the benchmark code used. It'll fake recalculating all visible
files' git status in treemacs (I've started using a real git call, but
awaiting the process' output would yield the thread automatically,
throwing off my tests):

(defun extra-slow-git-reapply ()
   (let ((run-start (float-time)))
     (with-current-buffer (treemacs-get-local-buffer)
       (dotimes (_ 30)
         (goto-char (point-min))
         (forward-line 1)
         (while (= 0 (forward-line 1))
           (-when-let* ((btn (treemacs-current-button))
                        (__no-projects (null (treemacs-button-get btn 
:project))))
             (let* ((inhibit-read-only t)
                    (status (prog1 (random 4) (dotimes (_ 10000) (random))))
                    (face (pcase status
                            (0 'font-lock-string-face)
                            (1 'font-lock-keyword-face)
                            (2 'font-lock-variable-name-face)
                            (3 'font-lock-builtin-face))))
               (put-text-property
                (treemacs-button-start btn)
                (treemacs-button-end btn)
                'face face))
             (let ((time (float-time)))
               (when t ;;(input-pending-p)
                 (thread-yield)
                 (message "Yield Time %ss" (- (float-time) time))))))))
     (message "Run Time %ss" (- (float-time) run-start))))

yyoncho writes:

 > Thank you, Alexander.
 >
 > I was planning to span a new thread but the approach with the queue 
might
 > be a better fit for us. Do you have the numbers for what will yield 
better
 > performance - checking input-pending and then thread-yield or directly
 > calling thread-yield?
 >
 > Ivan


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

* Re: Questions about throw-on-input
  2020-05-10 13:47 Alexander Miller
@ 2020-05-11 14:13 ` Eli Zaretskii
  2020-05-11 15:21   ` Stefan Monnier
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-11 14:13 UTC (permalink / raw)
  To: Alexander Miller; +Cc: yyoncho, emacs-devel

> From: Alexander Miller <alexanderm@web.de>
> Date: Sun, 10 May 2020 15:47:18 +0200
> Cc: emacs-devel@gnu.org
> 
> Checking (input-pending-p) does not work in this scenario. When your
> worker thread is actually busy (simulated by the 10000 calls to random
> below) input-pending-p will not return t, no matter how much you hammer
> the keyboard in the meatime. The yield-time message will not appear even
> once. So it looks like keeping the CPU busy also prevents the processing
> of input events.

It is unusual for non-main threads to wait for keyboard input
descriptor.  You shouldn't rely on that because it can only work very
rarely, if at all, and when it does, you are likely to see serious
problems.  Normally, the 'pselect' call issued by a non-main thread
will not mark the keyboard descriptor as being waited for.

At least, that's my understanding of the code and its implications.



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

* Re: Questions about throw-on-input
  2020-05-11 14:13 ` Eli Zaretskii
@ 2020-05-11 15:21   ` Stefan Monnier
  2020-05-11 16:19     ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Stefan Monnier @ 2020-05-11 15:21 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Alexander Miller, yyoncho, emacs-devel

> It is unusual for non-main threads to wait for keyboard input
> descriptor.  You shouldn't rely on that because it can only work very
> rarely, if at all, and when it does, you are likely to see serious
> problems.  Normally, the 'pselect' call issued by a non-main thread
> will not mark the keyboard descriptor as being waited for.

Should input-pending-p and friends catch that case and signal an error, then?


        Stefan




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

* Re: Questions about throw-on-input
  2020-05-11 15:21   ` Stefan Monnier
@ 2020-05-11 16:19     ` Eli Zaretskii
  2020-05-11 17:27       ` Stefan Monnier
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-11 16:19 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: alexanderm, yyoncho, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Alexander Miller <alexanderm@web.de>,  yyoncho@gmail.com,
>   emacs-devel@gnu.org
> Date: Mon, 11 May 2020 11:21:33 -0400
> 
> > It is unusual for non-main threads to wait for keyboard input
> > descriptor.  You shouldn't rely on that because it can only work very
> > rarely, if at all, and when it does, you are likely to see serious
> > problems.  Normally, the 'pselect' call issued by a non-main thread
> > will not mark the keyboard descriptor as being waited for.
> 
> Should input-pending-p and friends catch that case and signal an error, then?

Do we want that?



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

* Re: Questions about throw-on-input
  2020-05-11 16:19     ` Eli Zaretskii
@ 2020-05-11 17:27       ` Stefan Monnier
  2020-05-11 17:39         ` Alexander Miller
  2020-05-11 18:17         ` Eli Zaretskii
  0 siblings, 2 replies; 52+ messages in thread
From: Stefan Monnier @ 2020-05-11 17:27 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: alexanderm, yyoncho, emacs-devel

>> > It is unusual for non-main threads to wait for keyboard input
>> > descriptor.  You shouldn't rely on that because it can only work very
>> > rarely, if at all, and when it does, you are likely to see serious
>> > problems.  Normally, the 'pselect' call issued by a non-main thread
>> > will not mark the keyboard descriptor as being waited for.
>> Should input-pending-p and friends catch that case and signal an error, then?
> Do we want that?

I don't know.  But hanging because `select` doesn't return the needed
information doesn't seem right either.

Maybe rather than signal an error, we should somehow make the main
thread run that code, so as to return the right answer?


        Stefan




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

* Re: Questions about throw-on-input
  2020-05-11 17:27       ` Stefan Monnier
@ 2020-05-11 17:39         ` Alexander Miller
  2020-05-11 18:23           ` Eli Zaretskii
                             ` (2 more replies)
  2020-05-11 18:17         ` Eli Zaretskii
  1 sibling, 3 replies; 52+ messages in thread
From: Alexander Miller @ 2020-05-11 17:39 UTC (permalink / raw)
  To: monnier; +Cc: eliz, yyoncho, emacs-devel

 >> Do we want that?
 >
 > I don't know. But hanging because `select` doesn't return the needed
 > information doesn't seem right either. Maybe rather than signal an
 > error, we should somehow make the main thread run that code, so as to
 > return the right answer?

That could be a game-changer, it would open up the path for making Elisp
a lot more asynchronous than it is now. You could load up heavy work on
a background thread, and (of course assuming it can be slit into smaller
pieces) simply yield whenever input is detected. And when the main
thread has done its part the worker would simply pick up again where it
left off.

That is something of a holy grail for many package developers like me -
to be able to *do things*, especially in the background, without
constant worry of freezing the UI.

I don't think this is possible right now, other than maybe with
awkwardly pushing around timers and while-no-input, or using mandatory
1ms pauses instead of proper yielding as in my benchmark, which is
probably not exactly ideal either.

And while we are on the topic of threads, I wonder what is the
maintainers' opinion on https://nullprogram.com/blog/2018/05/31/,
specifically this part:

 > Update: ThreadSanitizer (TSan) quickly shows that Emacs’ threading
 > implementation has many data races, making it completely
 > untrustworthy. Until this is fixed, nobody should use Emacs threads
 > for any purpose, and threads should disabled at compile time.




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

* Re: Questions about throw-on-input
  2020-05-11 17:27       ` Stefan Monnier
  2020-05-11 17:39         ` Alexander Miller
@ 2020-05-11 18:17         ` Eli Zaretskii
  1 sibling, 0 replies; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-11 18:17 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: alexanderm, yyoncho, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: alexanderm@web.de,  yyoncho@gmail.com,  emacs-devel@gnu.org
> Date: Mon, 11 May 2020 13:27:05 -0400
> 
> >> > It is unusual for non-main threads to wait for keyboard input
> >> > descriptor.  You shouldn't rely on that because it can only work very
> >> > rarely, if at all, and when it does, you are likely to see serious
> >> > problems.  Normally, the 'pselect' call issued by a non-main thread
> >> > will not mark the keyboard descriptor as being waited for.
> >> Should input-pending-p and friends catch that case and signal an error, then?
> > Do we want that?
> 
> I don't know.  But hanging because `select` doesn't return the needed
> information doesn't seem right either.

I don't understand: input-pending-p doesn't hang.  Were you thinking
about while-no-input?

> Maybe rather than signal an error, we should somehow make the main
> thread run that code, so as to return the right answer?

Maybe.  But that could be tricky, implementation-wise.



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

* Re: Questions about throw-on-input
  2020-05-11 17:39         ` Alexander Miller
@ 2020-05-11 18:23           ` Eli Zaretskii
  2020-05-11 18:24           ` Stefan Monnier
  2020-05-12  2:39           ` Daniel Colascione
  2 siblings, 0 replies; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-11 18:23 UTC (permalink / raw)
  To: Alexander Miller; +Cc: emacs-devel, monnier, yyoncho

> Cc: eliz@gnu.org, yyoncho@gmail.com, emacs-devel@gnu.org
> From: Alexander Miller <alexanderm@web.de>
> Date: Mon, 11 May 2020 19:39:22 +0200
> 
> And while we are on the topic of threads, I wonder what is the
> maintainers' opinion on https://nullprogram.com/blog/2018/05/31/,
> specifically this part:
> 
>  > Update: ThreadSanitizer (TSan) quickly shows that Emacs’ threading
>  > implementation has many data races, making it completely
>  > untrustworthy. Until this is fixed, nobody should use Emacs threads
>  > for any purpose, and threads should disabled at compile time.

All true, except that the last sentence is the author's personal
opinion, of course, not a fact.  That and the "untrustworthy" thing,
which is completely out of place.

If someone thinks he or she can fix those races, I invite them to do
so ASAP, such changes will be very welcome.  I had my share if messing
with that.



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

* Re: Questions about throw-on-input
  2020-05-11 17:39         ` Alexander Miller
  2020-05-11 18:23           ` Eli Zaretskii
@ 2020-05-11 18:24           ` Stefan Monnier
  2020-05-11 19:48             ` Alexander Miller
  2020-05-12  2:39           ` Daniel Colascione
  2 siblings, 1 reply; 52+ messages in thread
From: Stefan Monnier @ 2020-05-11 18:24 UTC (permalink / raw)
  To: Alexander Miller; +Cc: eliz, yyoncho, emacs-devel

> That could be a game-changer, it would open up the path for making Elisp
> a lot more asynchronous than it is now. You could load up heavy work on
> a background thread, and (of course assuming it can be slit into smaller
> pieces) simply yield whenever input is detected. And when the main
> thread has done its part the worker would simply pick up again where it
> left off.

I think calling `thread-yield` frequently enough should(!) do the trick.
No need to call `input-pending-p`.

IOW if `thread-yield` doesn't do the trick, you should
likely `M-x report-emacs-bug`.

> I don't think this is possible right now, other than maybe with
> awkwardly pushing around timers and while-no-input, or using mandatory
> 1ms pauses instead of proper yielding as in my benchmark, which is
> probably not exactly ideal either.

Actually a better solution is often to run in a separate process
(e.g. via `async.el`).  That also lets you use the various CPU cores
lying idle ;-)

> And while we are on the topic of threads, I wonder what is the
> maintainers' opinion on https://nullprogram.com/blog/2018/05/31/,
> specifically this part:
>> Update: ThreadSanitizer (TSan) quickly shows that Emacs’ threading
>> implementation has many data races, making it completely
>> untrustworthy. Until this is fixed, nobody should use Emacs threads
>> for any purpose, and threads should disabled at compile time.

Sounds very credible, but I'll let someone else take care of this,
because it's too far from my area of expertise.


        Stefan




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

* Re: Questions about throw-on-input
  2020-05-11 18:24           ` Stefan Monnier
@ 2020-05-11 19:48             ` Alexander Miller
  2020-05-11 20:14               ` Stefan Monnier
  0 siblings, 1 reply; 52+ messages in thread
From: Alexander Miller @ 2020-05-11 19:48 UTC (permalink / raw)
  To: monnier; +Cc: eliz, yyoncho, emacs-devel

 > Actually a better solution is often to run in a separate process
 > (e.g. via `async.el`). That also lets you use the various CPU cores
 > lying idle ;-)

async.el starts slowly, has no good way to read the current state
like text properties or buffer content, has no knowledge about loaded
libraries and incurs double serialization overhead. If just a Hello
World needs 70ms on my system imagine what it's like doing something
with org. That is far from ideal.

For context: I am mostly thinking about passive work in my treemacs
package that happens without any user interaction, like re-rendering on
changes in the file system or a file's tags, passively fontifying files
based on their git status after some directory node has been opened or
following the file the user is currently editing. All of that happens
passively, so I consider any perceptible delay a no-go. Being able to
just stop the git-fontify when the user types and later pick it up would
be a major help.

 > I think calling `thread-yield` frequently enough should(!) do the trick.
 > No need to call `input-pending-p`.
 >
 > IOW if `thread-yield` doesn't do the trick, you should
 > likely `M-x report-emacs-bug`.

Yielding doesn't work for me, my input is ignored most of the time. I
will make my code emacs-q ready and open a bug report for it tomorrow.

 > Sounds very credible, but I'll let someone else take care of this,
 > because it's too far from my area of expertise.

Same for me I'm afraid.




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

* Re: Questions about throw-on-input
  2020-05-11 19:48             ` Alexander Miller
@ 2020-05-11 20:14               ` Stefan Monnier
  2020-05-12 22:33                 ` Alexander Miller
  0 siblings, 1 reply; 52+ messages in thread
From: Stefan Monnier @ 2020-05-11 20:14 UTC (permalink / raw)
  To: Alexander Miller; +Cc: eliz, yyoncho, emacs-devel

>> Actually a better solution is often to run in a separate process
>> (e.g. via `async.el`). That also lets you use the various CPU cores
>> lying idle ;-)
> async.el starts slowly,

Right, but you were talking about a presumably longish-running
background job, so the startup should be "negligible".

> has no good way to read the current state like text properties or
> buffer content, has no knowledge about loaded libraries and incurs
> double serialization overhead.

Yes, it has its share of hurdles.

>> IOW if `thread-yield` doesn't do the trick, you should
>> likely `M-x report-emacs-bug`.
> Yielding doesn't work for me, my input is ignored most of the time. I
> will make my code emacs-q ready and open a bug report for it tomorrow.

Thanks,


        Stefan




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

* Re: Questions about throw-on-input
  2020-05-11 17:39         ` Alexander Miller
  2020-05-11 18:23           ` Eli Zaretskii
  2020-05-11 18:24           ` Stefan Monnier
@ 2020-05-12  2:39           ` Daniel Colascione
  2020-05-12 14:37             ` Eli Zaretskii
  2 siblings, 1 reply; 52+ messages in thread
From: Daniel Colascione @ 2020-05-12  2:39 UTC (permalink / raw)
  To: Alexander Miller, monnier; +Cc: eliz, yyoncho, emacs-devel

On 5/11/20 10:39 AM, Alexander Miller wrote:
>  >> Do we want that?
>  >
>  > I don't know. But hanging because `select` doesn't return the needed
>  > information doesn't seem right either. Maybe rather than signal an
>  > error, we should somehow make the main thread run that code, so as to
>  > return the right answer?
> 
> That could be a game-changer, it would open up the path for making Elisp
> a lot more asynchronous than it is now. You could load up heavy work on
> a background thread, and (of course assuming it can be slit into smaller
> pieces) simply yield whenever input is detected. 

Sure. You can also have Emacs run itself as a subprocess.

> And while we are on the topic of threads, I wonder what is the
> maintainers' opinion on https://nullprogram.com/blog/2018/05/31/,
> specifically this part:
> 
>  > Update: ThreadSanitizer (TSan) quickly shows that Emacs’ threading
>  > implementation has many data races, making it completely
>  > untrustworthy. Until this is fixed, nobody should use Emacs threads
>  > for any purpose, and threads should disabled at compile time.

Is TSan is just getting confused by the global lock? We don't have any 
parallelism, so data races shouldn't be happening at all.



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

* Re: Questions about throw-on-input
  2020-05-08  1:58     ` Stefan Monnier
  2020-05-08  4:36       ` yyoncho
@ 2020-05-12  4:15       ` Michael Heerdegen
  1 sibling, 0 replies; 52+ messages in thread
From: Michael Heerdegen @ 2020-05-12  4:15 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, yyoncho, emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> It can be implemented, but it won't have the desired semantics.
> If you want something robust you have 2 options:
>
> - write in an event-driven style (or CPS style) so that you can easily
>   stop at various points in the program and stash the rest of the
>   computation for later.
>
> - use a thread (which will basically do the same, but transparently,
>   i.e. without the awkward programming style.)

Another variant that may fit sometimes is using stream.el streams.  They
have state (via lexical binding/closures), but you are also forced to
use a certain style that may not work well for every problem, but it is
very simple.

The actual program then successively generates the elements of the
stream in a `while-no-input'.


Michael.



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

* Re: Questions about throw-on-input
  2020-05-12  2:39           ` Daniel Colascione
@ 2020-05-12 14:37             ` Eli Zaretskii
  0 siblings, 0 replies; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-12 14:37 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: alexanderm, emacs-devel, monnier, yyoncho

> Cc: eliz@gnu.org, yyoncho@gmail.com, emacs-devel@gnu.org
> From: Daniel Colascione <dancol@dancol.org>
> Date: Mon, 11 May 2020 19:39:33 -0700
> 
> > And while we are on the topic of threads, I wonder what is the
> > maintainers' opinion on https://nullprogram.com/blog/2018/05/31/,
> > specifically this part:
> > 
> >  > Update: ThreadSanitizer (TSan) quickly shows that Emacs’ threading
> >  > implementation has many data races, making it completely
> >  > untrustworthy. Until this is fixed, nobody should use Emacs threads
> >  > for any purpose, and threads should disabled at compile time.
> 
> Is TSan is just getting confused by the global lock? We don't have any 
> parallelism, so data races shouldn't be happening at all.

There doesn't seem to be any detailed description of the races it
uncovered, so it could well be that this is a red herring.

I do know about some racy conditions where we release the GIL and
select the next thread to run, but I'm cannot be sure they are the
same ones this blog is talking about.



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

* Re: Questions about throw-on-input
  2020-05-11 20:14               ` Stefan Monnier
@ 2020-05-12 22:33                 ` Alexander Miller
  2020-05-13 14:43                   ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Alexander Miller @ 2020-05-12 22:33 UTC (permalink / raw)
  To: monnier; +Cc: eliz, yyoncho, emacs-devel

Here is the promised bug report:
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=41220

 > Right, but you were talking about a presumably longish-running
 > background job, so the startup should be "negligible".

Ah, that was just the benchmark I made. I had to beef it up beyond the
point of a common or even-worst case scenario because it needed to run
long enough to feel how the thread performs.

A much more realistic case is probably a death by a thousand cuts kind
of deal: you have a package like treemacs needing to grab and display
some new git info, and a dired buffer that needs reverting, and a git
gutter that needs updating, and your mail package is refreshing its
index, and your syntax checker's overlays need moving, and the language
server is being very chatty, so when it takes your autocomplete popup 1
full second to appear you get inconvenienced. Not the end of the world,
but a reason for people to think emacs is slow and bloated.

In my ideal world all that stuff could be done non-blockingly in another
thread as much as possible, only needing to surface to the main UI
thread to make actual changes like inserting text/overlays/text
properties.




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

* Re: Questions about throw-on-input
  2020-05-12 22:33                 ` Alexander Miller
@ 2020-05-13 14:43                   ` Eli Zaretskii
  2020-05-13 18:47                     ` Alexander Miller
  2020-05-14  8:32                     ` Philipp Stephani
  0 siblings, 2 replies; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-13 14:43 UTC (permalink / raw)
  To: Alexander Miller; +Cc: emacs-devel, monnier, yyoncho

> Cc: eliz@gnu.org, yyoncho@gmail.com, emacs-devel@gnu.org
> From: Alexander Miller <alexanderm@web.de>
> Date: Wed, 13 May 2020 00:33:01 +0200
> 
> In my ideal world all that stuff could be done non-blockingly in another
> thread as much as possible, only needing to surface to the main UI
> thread to make actual changes like inserting text/overlays/text
> properties.

Your ideal world seems to be based on an editor design that is very
different from what Emacs is.  The absolute majority of objects which
an average Lisp program manipulates are globally visible -- buffers,
windows, frames, global variables, the obarray, etc., and doing that
in non-blocking ways is not really trivial.



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

* Re: Questions about throw-on-input
  2020-05-13 14:43                   ` Eli Zaretskii
@ 2020-05-13 18:47                     ` Alexander Miller
  2020-05-14  8:32                     ` Philipp Stephani
  1 sibling, 0 replies; 52+ messages in thread
From: Alexander Miller @ 2020-05-13 18:47 UTC (permalink / raw)
  To: eliz; +Cc: emacs-devel, monnier, yyoncho

 > Your ideal world seems to be based on an editor design that is very
 > different from what Emacs is. The absolute majority of objects which
 > an average Lisp program manipulates are globally visible -- buffers,
 > windows, frames, global variables, the obarray, etc., and doing that
 > in non-blocking ways is not really trivial.

Well I'm not going to abandon a tasty cake just because it doesn't come
with my favorite topping.

Besides, I wasn't trying to make Emacs itself non-blocking, but looking
for options to do it all myself, manually. And the trick with replacing
thread-yield with a 1ms sleep puts me pretty much 90% there.




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

* Re: Questions about throw-on-input
  2020-05-13 14:43                   ` Eli Zaretskii
  2020-05-13 18:47                     ` Alexander Miller
@ 2020-05-14  8:32                     ` Philipp Stephani
  2020-05-14 14:23                       ` Eli Zaretskii
  2020-05-14 16:56                       ` Drew Adams
  1 sibling, 2 replies; 52+ messages in thread
From: Philipp Stephani @ 2020-05-14  8:32 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Alexander Miller, yyoncho, Stefan Monnier, Emacs developers

Am Mi., 13. Mai 2020 um 16:44 Uhr schrieb Eli Zaretskii <eliz@gnu.org>:
>
> > Cc: eliz@gnu.org, yyoncho@gmail.com, emacs-devel@gnu.org
> > From: Alexander Miller <alexanderm@web.de>
> > Date: Wed, 13 May 2020 00:33:01 +0200
> >
> > In my ideal world all that stuff could be done non-blockingly in another
> > thread as much as possible, only needing to surface to the main UI
> > thread to make actual changes like inserting text/overlays/text
> > properties.
>
> Your ideal world seems to be based on an editor design that is very
> different from what Emacs is.  The absolute majority of objects which
> an average Lisp program manipulates are globally visible -- buffers,
> windows, frames, global variables, the obarray, etc., and doing that
> in non-blocking ways is not really trivial.
>

And that's what I'd call one of the biggest problems in current
Emacs's design. Much of the development in programming practices over
the last few decades has been moving away from global mutable state,
in order to increase robustness and predictability, and also to make
concurrency without subprocesses possible.



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

* Re: Questions about throw-on-input
  2020-05-14  8:32                     ` Philipp Stephani
@ 2020-05-14 14:23                       ` Eli Zaretskii
  2020-05-14 14:37                         ` Philipp Stephani
  2020-05-14 16:56                       ` Drew Adams
  1 sibling, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-14 14:23 UTC (permalink / raw)
  To: Philipp Stephani; +Cc: alexanderm, yyoncho, monnier, emacs-devel

> From: Philipp Stephani <p.stephani2@gmail.com>
> Date: Thu, 14 May 2020 10:32:44 +0200
> Cc: Alexander Miller <alexanderm@web.de>, Emacs developers <emacs-devel@gnu.org>, 
> 	Stefan Monnier <monnier@iro.umontreal.ca>, yyoncho <yyoncho@gmail.com>
> 
> > Your ideal world seems to be based on an editor design that is very
> > different from what Emacs is.  The absolute majority of objects which
> > an average Lisp program manipulates are globally visible -- buffers,
> > windows, frames, global variables, the obarray, etc., and doing that
> > in non-blocking ways is not really trivial.
> >
> 
> And that's what I'd call one of the biggest problems in current
> Emacs's design. Much of the development in programming practices over
> the last few decades has been moving away from global mutable state,
> in order to increase robustness and predictability, and also to make
> concurrency without subprocesses possible.

My point is that adding multithreading to Emacs will need rethinking
and redesigning many core features, so it is a large job.



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

* Re: Questions about throw-on-input
  2020-05-14 14:23                       ` Eli Zaretskii
@ 2020-05-14 14:37                         ` Philipp Stephani
  0 siblings, 0 replies; 52+ messages in thread
From: Philipp Stephani @ 2020-05-14 14:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Alexander Miller, yyoncho, Stefan Monnier, Emacs developers

Am Do., 14. Mai 2020 um 16:24 Uhr schrieb Eli Zaretskii <eliz@gnu.org>:
>
> > From: Philipp Stephani <p.stephani2@gmail.com>
> > Date: Thu, 14 May 2020 10:32:44 +0200
> > Cc: Alexander Miller <alexanderm@web.de>, Emacs developers <emacs-devel@gnu.org>,
> >       Stefan Monnier <monnier@iro.umontreal.ca>, yyoncho <yyoncho@gmail.com>
> >
> > > Your ideal world seems to be based on an editor design that is very
> > > different from what Emacs is.  The absolute majority of objects which
> > > an average Lisp program manipulates are globally visible -- buffers,
> > > windows, frames, global variables, the obarray, etc., and doing that
> > > in non-blocking ways is not really trivial.
> > >
> >
> > And that's what I'd call one of the biggest problems in current
> > Emacs's design. Much of the development in programming practices over
> > the last few decades has been moving away from global mutable state,
> > in order to increase robustness and predictability, and also to make
> > concurrency without subprocesses possible.
>
> My point is that adding multithreading to Emacs will need rethinking
> and redesigning many core features, so it is a large job.

Yes, I fully agree.

Just to reiterate, because I think this point can't be stressed
enough: It's not possible to just run existing code in background
threads and expect it to work. It's also not possible to have the
ELisp interpreter yield automatically. Even with a GIL, a yield means
that arbitrary state changes (point moving, buffers vanishing,
variable values changing, etc.) can happen. Therefore it's crucial
that the interpreter yield only at very specific points (roughly those
where other asynchronous code is allowed to run, e.g.
accept-process-output or sleep-for). Java/C++-style multithreading is
simply not possible with the current design of ELisp.
I'd therefore recommend to focus on a combination of explicit
asynchonicity without multithreading (using continuations or promises)
and webworker-style background processing (with complete state
isolation and explicit copying of data).



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

* RE: Questions about throw-on-input
  2020-05-14  8:32                     ` Philipp Stephani
  2020-05-14 14:23                       ` Eli Zaretskii
@ 2020-05-14 16:56                       ` Drew Adams
  2020-05-15  3:21                         ` Richard Stallman
  1 sibling, 1 reply; 52+ messages in thread
From: Drew Adams @ 2020-05-14 16:56 UTC (permalink / raw)
  To: Philipp Stephani, Eli Zaretskii
  Cc: Alexander Miller, Emacs developers, yyoncho, Stefan Monnier

> > Your ideal world seems to be based on an editor design that is very
> > different from what Emacs is.  The absolute majority of objects which
> > an average Lisp program manipulates are globally visible -- buffers,
> > windows, frames, global variables, the obarray, etc., and doing that
> > in non-blocking ways is not really trivial.
> 
> And that's what I'd call one of the biggest problems in current
> Emacs's design. Much of the development in programming practices over
> the last few decades has been moving away from global mutable state,
> in order to increase robustness and predictability, and also to make
> concurrency without subprocesses possible.

Ah, but Emacs and Emacs Lisp are not just about
programming and writing Elisp libraries.

Certainly, a purely functional (or purely
logic/relational) language has advantages
(many, many!) from a programming point of view.

But Emacs Lisp, and in particular the global
thingies you decry, and in particular dynamic
binding, are very useful for Emacs _users_,
for easy customization/extension.

Again, I point to the rationale:

https://www.gnu.org/software/emacs/emacs-paper.html#SEC17

https://www.gnu.org/software/emacs/emacs-paper.html#SEC18

Emacs Lisp is not Haskell, and it's not Scheme.
You may say, "Alas", but until you or someone
else comes up with a reasonably useful "editor"
on the order of Emacs and Elisp, but which uses
only pure Lisp (no side effects) or Haskell, I
remain skeptical.

The argument for the presence of such dynamic,
and sometimes global, thingies is not an argument
against lexical etc. or an argument in favor of
abusing or exaggerating the use of global etc.
thingies.  It's just to point out that they have
their place, in a context such as Emacs.  They're
not just things to be purged in some blanket
cleanup campaign.



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

* Re: Questions about throw-on-input
  2020-05-14 16:56                       ` Drew Adams
@ 2020-05-15  3:21                         ` Richard Stallman
  2020-05-15  3:54                           ` Stefan Monnier
  0 siblings, 1 reply; 52+ messages in thread
From: Richard Stallman @ 2020-05-15  3:21 UTC (permalink / raw)
  To: Drew Adams; +Cc: emacs-devel, p.stephani2, yyoncho, alexanderm, eliz, monnier

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

An editor buffer is global mutable state.  Global mutable state is at
the heart of GNU Emacs, and I disagree with the idea that we should
try to get away from it.  That is a non-goal.

Even if someone showed me that there is no significant inconvenience
in writing a text editor without global mutable state -- which I am
skeptical of -- I would be against putting effort into changing the
internal design of Emacs for goals that are internal.  We should
put our effort into features that provide benefits to users.

-- 
Dr Richard Stallman
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





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

* Re: Questions about throw-on-input
  2020-05-15  3:21                         ` Richard Stallman
@ 2020-05-15  3:54                           ` Stefan Monnier
  2020-05-15  8:19                             ` Arthur Miller
  0 siblings, 1 reply; 52+ messages in thread
From: Stefan Monnier @ 2020-05-15  3:54 UTC (permalink / raw)
  To: Richard Stallman
  Cc: emacs-devel, p.stephani2, yyoncho, alexanderm, eliz, Drew Adams

> An editor buffer is global mutable state.  Global mutable state is at
> the heart of GNU Emacs, and I disagree with the idea that we should
> try to get away from it.  That is a non-goal.

But the goal talked about here is concurrency.  Concurrency is not
incompatible with global state, but it's incompatible with global state
accessed from anywhere without any way to control it.

The problem, as I see it, is that we could imagine binding threads to
buffers such that a buffer can only be accessed by a single thread at
a time.

That would be reasonably easy to implement, I think, by putting a lock
on buffer objects (since there are fairly few ways to access a buffer:
you almost always have to make it current first).  But the buffer's
local variables can contain data such as hash-tables or cons-cells which
can be shared between various buffers, and that is a lot harder to
control because we don't want to put a lock on every cons cell.

Maybe we could have a notion of "buffer-local data/heap" and "global
read-only data/heap" or something like that and some way make sure that
a thread only operates of buffer-local data and global read-only data,
in which case it can indeed safely run concurrently with other Elisp
code operating in other buffers.


        Stefan




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

* Re: Questions about throw-on-input
  2020-05-15  3:54                           ` Stefan Monnier
@ 2020-05-15  8:19                             ` Arthur Miller
  2020-05-15 15:45                               ` Stefan Monnier
  0 siblings, 1 reply; 52+ messages in thread
From: Arthur Miller @ 2020-05-15  8:19 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Richard Stallman, emacs-devel, p.stephani2, yyoncho, alexanderm,
	eliz, Drew Adams

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> An editor buffer is global mutable state.  Global mutable state is at
>> the heart of GNU Emacs, and I disagree with the idea that we should
>> try to get away from it.  That is a non-goal.
>
> But the goal talked about here is concurrency.  Concurrency is not
> incompatible with global state, but it's incompatible with global state
> accessed from anywhere without any way to control it.
>
> The problem, as I see it, is that we could imagine binding threads to
> buffers such that a buffer can only be accessed by a single thread at
> a time.
>
> That would be reasonably easy to implement, I think, by putting a lock
> on buffer objects (since there are fairly few ways to access a buffer:
> you almost always have to make it current first).  But the buffer's
> local variables can contain data such as hash-tables or cons-cells which
> can be shared between various buffers, and that is a lot harder to
> control because we don't want to put a lock on every cons cell.
>
> Maybe we could have a notion of "buffer-local data/heap" and "global
> read-only data/heap" or something like that and some way make sure that
> a thread only operates of buffer-local data and global read-only data,
> in which case it can indeed safely run concurrently with other Elisp
> code operating in other buffers.
>
>
>         Stefan
I have a question, most for curiosity, it is is ok :-):

If you reversed the thought and started at "thread-end", could
you make every buffer be owned by some thread. Instead of buffer-first,
would it help to think thread-first? Thus Emacs process would become
more of a thread-scheduller, similar as some web browsers are using
separate process to render each webpage (in its own tab); I think Firfox
uses threads instead of processes. Maybe not the best way to use
multiprocessor cpus as of today, but certainly better then nothing at
all. Dont' know if it possible for Emacs and how underlaying "lisp
machine" is constructed. Maybe each thread could have it's own eval.
But then how would they communicate when they need, since Emacs
buffers often are used together in some way unlike webpages in a browser.

I hope you dont't mind interfering and my curiosity.



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

* Re: Questions about throw-on-input
  2020-05-15  8:19                             ` Arthur Miller
@ 2020-05-15 15:45                               ` Stefan Monnier
  2020-05-15 16:46                                 ` Yuan Fu
                                                   ` (2 more replies)
  0 siblings, 3 replies; 52+ messages in thread
From: Stefan Monnier @ 2020-05-15 15:45 UTC (permalink / raw)
  To: Arthur Miller
  Cc: Richard Stallman, emacs-devel, p.stephani2, yyoncho, alexanderm,
	eliz, Drew Adams

> Dont' know if it possible for Emacs and how underlaying "lisp
> machine" is constructed. Maybe each thread could have it's own eval.
> But then how would they communicate when they need, since Emacs
> buffers often are used together in some way unlike webpages in a browser.

That's the problem: in the current design of Emacs and Elisp, we can
and do share data between buffers.

In the web-browser, each "tab" is its own virtual-machine, with very
little communication between them and very little sharing.

In Emacs, on the contrary all the functions and the global data defined
by the loaded packages are shared, and additionally to that some of the
buffer-local data is also shared.


        Stefan




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

* Re: Questions about throw-on-input
  2020-05-15 15:45                               ` Stefan Monnier
@ 2020-05-15 16:46                                 ` Yuan Fu
  2020-05-15 17:31                                   ` Stefan Monnier
  2020-05-15 17:35                                 ` Arthur Miller
  2020-05-15 19:47                                 ` chad
  2 siblings, 1 reply; 52+ messages in thread
From: Yuan Fu @ 2020-05-15 16:46 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Richard Stallman, emacs-devel, p.stephani2, yyoncho,
	Arthur Miller, alexanderm, Eli Zaretskii, Drew Adams

Do we have to share data between threads? A thread doesn’t share any data can still be useful, speeding up some computations. For example, generating completion candidates, providing async completion.

Yuan


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

* Re: Questions about throw-on-input
  2020-05-15 16:46                                 ` Yuan Fu
@ 2020-05-15 17:31                                   ` Stefan Monnier
  2020-05-15 17:50                                     ` yyoncho
  2020-05-15 18:00                                     ` Andrea Corallo
  0 siblings, 2 replies; 52+ messages in thread
From: Stefan Monnier @ 2020-05-15 17:31 UTC (permalink / raw)
  To: Yuan Fu
  Cc: Richard Stallman, emacs-devel, p.stephani2, yyoncho,
	Arthur Miller, alexanderm, Eli Zaretskii, Drew Adams

> Do we have to share data between threads? A thread doesn’t share any data
> can still be useful, speeding up some computations. For example, generating
> completion candidates, providing async completion.

If you don't need to share anything, than `async.el` does the trick.
But in most cases, in order to be able to show completion candidates,
you need to get access to some data.


        Stefan




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

* Re: Questions about throw-on-input
  2020-05-15 15:45                               ` Stefan Monnier
  2020-05-15 16:46                                 ` Yuan Fu
@ 2020-05-15 17:35                                 ` Arthur Miller
  2020-05-15 19:47                                 ` chad
  2 siblings, 0 replies; 52+ messages in thread
From: Arthur Miller @ 2020-05-15 17:35 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Richard Stallman, emacs-devel, p.stephani2, yyoncho, alexanderm,
	eliz, Drew Adams

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Dont' know if it possible for Emacs and how underlaying "lisp
>> machine" is constructed. Maybe each thread could have it's own eval.
>> But then how would they communicate when they need, since Emacs
>> buffers often are used together in some way unlike webpages in a browser.
>
> That's the problem: in the current design of Emacs and Elisp, we can
> and do share data between buffers.
>
> In the web-browser, each "tab" is its own virtual-machine, with very
> little communication between them and very little sharing.
>
> In Emacs, on the contrary all the functions and the global data defined
> by the loaded packages are shared, and additionally to that some of the
> buffer-local data is also shared.
>
>
>         Stefan

Thank you for the clarification.




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

* Re: Questions about throw-on-input
  2020-05-15 17:31                                   ` Stefan Monnier
@ 2020-05-15 17:50                                     ` yyoncho
  2020-05-15 18:44                                       ` Alexander Miller
  2020-05-15 18:00                                     ` Andrea Corallo
  1 sibling, 1 reply; 52+ messages in thread
From: yyoncho @ 2020-05-15 17:50 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Yuan Fu, Richard Stallman, emacs-devel, Philipp Stephani,
	Arthur Miller, Alexander Miller, Eli Zaretskii, Drew Adams

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

Hi Stefan,


If you don't need to share anything, than `async.el` does the trick.
> But in most cases, in order to be able to show completion candidates,
> you need to get access to some data.
>

FWIW if we consider the lsp-mode scenario the ability to start a separate
thread which does not share anything with the main thread and introducing
mechanisms for sending/receiving messages(either by copying the data or by
transferring the ownership) will be very useful and won't break any
existing elisp code. All this is similar to what emacs async is but
without the interprocess and serialization overhead which is a dealbreaker
for the described scenario. IMO this will be very useful even with some
restrictions like not allowing buffer transfer.

Thanks,
Ivan

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

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

* Re: Questions about throw-on-input
  2020-05-15 17:31                                   ` Stefan Monnier
  2020-05-15 17:50                                     ` yyoncho
@ 2020-05-15 18:00                                     ` Andrea Corallo
  1 sibling, 0 replies; 52+ messages in thread
From: Andrea Corallo @ 2020-05-15 18:00 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Yuan Fu, Richard Stallman, emacs-devel, p.stephani2, yyoncho,
	Arthur Miller, alexanderm, Eli Zaretskii, Drew Adams

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Do we have to share data between threads? A thread doesn’t share any data
>> can still be useful, speeding up some computations. For example, generating
>> completion candidates, providing async completion.
>
> If you don't need to share anything, than `async.el` does the trick.
> But in most cases, in order to be able to show completion candidates,
> you need to get access to some data.

What about having a quick de/serializer we can use to serialize and send
data to another process or thread?  This could perform the requested job
and give back the data using this same binary format.

The pdumper would be the first candidate to look at to be generalized
for this purpose.

We would probably need also some specific way to limit the deepness of
the copy in certain cases, this not to end-up serializing the whole heap.

  Andrea

--
akrl@sdf.org



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

* Re: Questions about throw-on-input
  2020-05-15 17:50                                     ` yyoncho
@ 2020-05-15 18:44                                       ` Alexander Miller
  2020-05-15 18:55                                         ` Stefan Monnier
  2020-05-15 19:46                                         ` Philipp Stephani
  0 siblings, 2 replies; 52+ messages in thread
From: Alexander Miller @ 2020-05-15 18:44 UTC (permalink / raw)
  To: yyoncho
  Cc: casouri, rms, emacs-devel, p.stephani2, monnier, arthur.miller,
	eliz, drew.adams

I think every one's been talking about sharing data so far, but what
about the other part of the equation 'shared + mutable state = Bad'? Do
you think it would be feasible to remove mutability by giving side
threads only read-only access to all that global shared data?

Threads like these would still be plenty useful, you could still handle
language server communication (or semantic parsing, or imenu scanning
etc.) in the background with much less danger of stutter and a much
smaller problem area w.r.t. concurrency.

Does that make sense?




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

* Re: Questions about throw-on-input
  2020-05-15 18:44                                       ` Alexander Miller
@ 2020-05-15 18:55                                         ` Stefan Monnier
  2020-05-15 19:46                                         ` Philipp Stephani
  1 sibling, 0 replies; 52+ messages in thread
From: Stefan Monnier @ 2020-05-15 18:55 UTC (permalink / raw)
  To: Alexander Miller
  Cc: casouri, rms, emacs-devel, p.stephani2, yyoncho, arthur.miller,
	eliz, drew.adams

> I think every one's been talking about sharing data so far, but what
> about the other part of the equation 'shared + mutable state = Bad'? Do
> you think it would be feasible to remove mutability by giving side
> threads only read-only access to all that global shared data?

Just restricting side threads to read-only access is not sufficient: the
"main thread" also can't mutate that read-only data (or at least not
while the side threads can read it) otherwise we're back to "bad".

I like immutability, tho.  And there's no doubt that it would have to be
part of the solution if we want to allow sharing.


        Stefan




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

* Re: Questions about throw-on-input
  2020-05-15 18:44                                       ` Alexander Miller
  2020-05-15 18:55                                         ` Stefan Monnier
@ 2020-05-15 19:46                                         ` Philipp Stephani
  1 sibling, 0 replies; 52+ messages in thread
From: Philipp Stephani @ 2020-05-15 19:46 UTC (permalink / raw)
  To: Alexander Miller
  Cc: casouri, Richard Stallman, Emacs developers, yyoncho,
	arthur.miller, Eli Zaretskii, Drew Adams, Stefan Monnier

Am Fr., 15. Mai 2020 um 20:43 Uhr schrieb Alexander Miller <alexanderm@web.de>:
>
> I think every one's been talking about sharing data so far, but what
> about the other part of the equation 'shared + mutable state = Bad'? Do
> you think it would be feasible to remove mutability by giving side
> threads only read-only access to all that global shared data?

I don't think that would be enough. Immutable data truly needs to be
immutable, for all threads and forever. Otherwise the side threads
would still encounter random state changes made by the main thread.



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

* Re: Questions about throw-on-input
  2020-05-15 15:45                               ` Stefan Monnier
  2020-05-15 16:46                                 ` Yuan Fu
  2020-05-15 17:35                                 ` Arthur Miller
@ 2020-05-15 19:47                                 ` chad
  2020-05-16 11:29                                   ` Eli Zaretskii
  2 siblings, 1 reply; 52+ messages in thread
From: chad @ 2020-05-15 19:47 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Richard Stallman, EMACS development team, p.stephani2, yyoncho,
	Arthur Miller, alexanderm, Eli Zaretskii, Drew Adams

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

I was thinking about this recently, and, as a thought exercise, a
hypothetical emacs could adopt more of the web-browser model, based around
frames or windows rather than buffers. Things like completion windows would
be attached to a frame/window, but that's not conceptually hard, and
"better pop-up windows" is a nice-to-have anyway (people keep implementing
bespoke solutions for current emacs, and I believe a good internal facility
would be welcome).

I say "frame or window" because most editing use cases are built around a
single window with some transient extras (editing src/xdisp.c), with a few
common cases where multiple buffers are semantically linked (gnus, mu4e,
maybe slime/cider/gud) in a way that would be fine to share a single
thread, especially if the engine allowed for "workers" that could grab
(copy?) state, carry out some processing in the background, and then update
and release the state, similar to package-list-packages updating the
package list in the background while I look at various package-descriptions
in the foreground, or git updating while I read a log/diff.

By way of explanation (not endorsement), the email client I'm using right
now popped up a little message in the bottom-right corner that says "New
Message from Stefan Monnier  _Show_ _Ignore_", letting me know that the
state has been updated behind my view, and giving me the option to update
the view now or leave me alone while I finish my edits.

The idea here is to create potential boundaries between the giant
shared-mutable soup ala Oberon, Squeak, and (from what I understand) LispM,
while still allowing useful shared state. In this hypothetical world, what
are the cases where making most mutable data frame/window-local and
building a minimal shared arena for explict lock/mod/copy state would break
down? I can imagine that a list of current buffers, for example, would need
to cross that boundary. Would project-wide search, edit, and refactoring
tools be too constrained if a project had to live within a single
frame/window? Does the tab-bar/tab-line interface help us figure out how to
present the boundaries to the user in a helpful way?

Thanks,
~Chad

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

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

* Re: Questions about throw-on-input
  2020-05-15 19:47                                 ` chad
@ 2020-05-16 11:29                                   ` Eli Zaretskii
  0 siblings, 0 replies; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-16 11:29 UTC (permalink / raw)
  To: chad
  Cc: rms, emacs-devel, p.stephani2, yyoncho, arthur.miller, alexanderm,
	drew.adams, monnier

> From: chad <yandros@gmail.com>
> Date: Fri, 15 May 2020 12:47:08 -0700
> Cc: Arthur Miller <arthur.miller@live.com>, Richard Stallman <rms@gnu.org>, 
> 	EMACS development team <emacs-devel@gnu.org>, p.stephani2@gmail.com, yyoncho@gmail.com, 
> 	alexanderm@web.de, Eli Zaretskii <eliz@gnu.org>, Drew Adams <drew.adams@oracle.com>
> 
> The idea here is to create potential boundaries between the giant shared-mutable soup ala Oberon, Squeak,
> and (from what I understand) LispM, while still allowing useful shared state. In this hypothetical world, what
> are the cases where making most mutable data frame/window-local and building a minimal shared arena for
> explict lock/mod/copy state would break down? I can imagine that a list of current buffers, for example, would
> need to cross that boundary. Would project-wide search, edit, and refactoring tools be too constrained if a
> project had to live within a single frame/window? Does the tab-bar/tab-line interface help us figure out how to
> present the boundaries to the user in a helpful way?

I admit that I don't really understand what you are suggesting.  The
Web browser model doesn't really help since, as Stefan pointed out,
almost nothing is shared between different pages being shown in
different windows/tabs in a browser, in stark contrast to what happens
in Emacs.

Making threads local to windows immediately brings up a question about
the same buffer being shown in more than one window, something I tend
to do a lot when studying code or writing something in one place of a
buffer by looking at what another place does.

Another piece of the global shared state is all the lists we maintain
that make Emacs help us, like suggest defaults by using history.  Most
of that will be severely punished by limiting those lists to a single
window, especially if you consider that windows are ephemeral and get
deleted a lot.

Even redisplay is a problem: while on GUI frames it works on each
window independently from others, that is not so on TTY frames, where
optimal redrawing of the screen dictates us to redraw on the frame
level.

So I think your proposal will need to be much more detailed before it
can be seriously considered.  Which is actually one of the more
profound lessons I learned from hacking Emacs: it is never enough to
have the general idea of how things work, no matter how accurate that
general idea is.  The devil is in the details, and those details will
present tough problems, some of which will invalidate the proposed
solutions.  You must consider at least the main of those details up
front, or your solution will be revealed as unworkable after a lot of
efforts were already invested.

My suggestion is to take a small number of common commands and see how
much of the global state is involved in their execution, both on the
Lisp level and on the C level.  Then you might have a better idea how
to subdivide the global state, and maybe even whether it is feasible
to subdivide it into any meaningful parts.



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

end of thread, other threads:[~2020-05-16 11:29 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-09 13:09 Questions about throw-on-input Alexander Miller
2020-05-10 11:11 ` yyoncho
  -- strict thread matches above, loose matches on Subject: below --
2020-05-10 13:47 Alexander Miller
2020-05-11 14:13 ` Eli Zaretskii
2020-05-11 15:21   ` Stefan Monnier
2020-05-11 16:19     ` Eli Zaretskii
2020-05-11 17:27       ` Stefan Monnier
2020-05-11 17:39         ` Alexander Miller
2020-05-11 18:23           ` Eli Zaretskii
2020-05-11 18:24           ` Stefan Monnier
2020-05-11 19:48             ` Alexander Miller
2020-05-11 20:14               ` Stefan Monnier
2020-05-12 22:33                 ` Alexander Miller
2020-05-13 14:43                   ` Eli Zaretskii
2020-05-13 18:47                     ` Alexander Miller
2020-05-14  8:32                     ` Philipp Stephani
2020-05-14 14:23                       ` Eli Zaretskii
2020-05-14 14:37                         ` Philipp Stephani
2020-05-14 16:56                       ` Drew Adams
2020-05-15  3:21                         ` Richard Stallman
2020-05-15  3:54                           ` Stefan Monnier
2020-05-15  8:19                             ` Arthur Miller
2020-05-15 15:45                               ` Stefan Monnier
2020-05-15 16:46                                 ` Yuan Fu
2020-05-15 17:31                                   ` Stefan Monnier
2020-05-15 17:50                                     ` yyoncho
2020-05-15 18:44                                       ` Alexander Miller
2020-05-15 18:55                                         ` Stefan Monnier
2020-05-15 19:46                                         ` Philipp Stephani
2020-05-15 18:00                                     ` Andrea Corallo
2020-05-15 17:35                                 ` Arthur Miller
2020-05-15 19:47                                 ` chad
2020-05-16 11:29                                   ` Eli Zaretskii
2020-05-12  2:39           ` Daniel Colascione
2020-05-12 14:37             ` Eli Zaretskii
2020-05-11 18:17         ` Eli Zaretskii
2020-05-07  7:31 Ivan Yonchovski
2020-05-07 12:36 ` Eli Zaretskii
2020-05-07 14:28   ` Ivan Yonchovski
2020-05-07 21:11   ` yyoncho
2020-05-08  1:58     ` Stefan Monnier
2020-05-08  4:36       ` yyoncho
2020-05-08  4:43         ` yyoncho
2020-05-12  4:15       ` Michael Heerdegen
2020-05-08 10:41     ` Eli Zaretskii
2020-05-08 11:23       ` Ivan Yonchovski
2020-05-08 11:45         ` Eli Zaretskii
2020-05-08 11:55           ` yyoncho
2020-05-08 14:55         ` Stefan Monnier
2020-05-08 18:04           ` yyoncho
2020-05-07 13:49 ` Stefan Monnier
2020-05-07 15:36   ` Ivan Yonchovski

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).