Recent additions/changes (see personal repo) Marc Nieper-Wißkirchen (11 Nov 2022 17:19 UTC)
Re: Recent additions/changes (see personal repo) Shiro Kawai (14 Nov 2022 19:05 UTC)
Re: Recent additions/changes (see personal repo) Marc Nieper-Wißkirchen (14 Nov 2022 19:11 UTC)
Re: Recent additions/changes (see personal repo) Shiro Kawai (15 Nov 2022 08:31 UTC)
Re: Recent additions/changes (see personal repo) Marc Feeley (17 Nov 2022 13:22 UTC)
Re: Recent additions/changes (see personal repo) Marc Nieper-Wißkirchen (17 Nov 2022 13:51 UTC)
Re: Recent additions/changes (see personal repo) Marc Feeley (17 Nov 2022 14:24 UTC)
Re: Recent additions/changes (see personal repo) Marc Nieper-Wißkirchen (17 Nov 2022 14:44 UTC)
Re: Recent additions/changes (see personal repo) Marc Feeley (17 Nov 2022 15:38 UTC)
Re: Recent additions/changes (see personal repo) Marc Nieper-Wißkirchen (17 Nov 2022 16:26 UTC)
Re: Recent additions/changes (see personal repo) Shiro Kawai (17 Nov 2022 20:12 UTC)
Re: Recent additions/changes (see personal repo) Marc Nieper-Wißkirchen (17 Nov 2022 20:32 UTC)
Re: Recent additions/changes (see personal repo) Shiro Kawai (17 Nov 2022 23:02 UTC)
Re: Recent additions/changes (see personal repo) Shiro Kawai (17 Nov 2022 23:13 UTC)
Re: Recent additions/changes (see personal repo) Marc Feeley (17 Nov 2022 20:43 UTC)

Re: Recent additions/changes (see personal repo) Marc Feeley 17 Nov 2022 14:23 UTC

Marc

> On Nov 17, 2022, at 8:51 AM, Marc Nieper-Wißkirchen <xxxxxx@gmail.com> wrote:
>
> Am Do., 17. Nov. 2022 um 14:22 Uhr schrieb Marc Feeley
> <xxxxxx@iro.umontreal.ca>:
>>
>>
>>> On Nov 11, 2022, at 12:19 PM, Marc Nieper-Wißkirchen <xxxxxx@gmail.com> wrote:
>>>
>>> I have documented thread-interrupt! in 5.14.6.
>>>
>>> Thread-exit! is now renamed to thread-stop!.
>>>
>>> I hope that only editorial changes remain before we finalize this.
>>>
>>
>> I have problems understanding the spec for thread-interrupt!:
>>
>> (thread-interrupt! thread thunk)      procedure
>>
>> Schedules an interrupt for thread for when the current-interrupt-level of thread is zero. The current continuation of thread is then replaced by a continuation that records the values it receives, invokes thunk with no arguments, discards its values, and then yields the recorded values to the original continuation.
>>
>> Note: An interrupt can occur while a thread is blocked waiting on a condition variable.
>>
>>
>> It mentions “replacing” the current continuation of the target thread by a new one.  I don’t understand that model which seems to assume that the computation moves from continuation to continuation (i.e. that calling a continuation marks the beginning of a computational step).  I think it also assumes that every point where a continuation is called is a “safe point” where the Scheme VM is in a consistent state.  But when a program is written in continuation passing style the implicit continuations are never called because the computation is strictly a sequence of tail calls with no returns.  Also the simple infinite loop (let loop () (loop)) never calls a continuation… so does that mean it can’t be interrupted?
>
> A continuation is not called; a piece of code is evaluated in a
> continuation.  After each evaluation step (the spec is silent on how
> fine-grained this is), there will again be a continuation (possibly
> the same) waiting for the result of some evaluation step.  In essence,
> I mean the same as your syntactic replacement of <expr> by (begin
> (poll-interrupts!) <expr>).  To make it precise, we would really have
> to amend the formal semantics of Scheme.
>

I understand.  In that case it would be good to add a reminder of this stepping model.

>> I think a better way to explain it is that every expression <expr> in the program is conceptually treated as (begin (poll-interrupts!) <expr>) and then give a definition of (poll-interrupts!) that checks the current-interrupt-level and calls any pending interrupt thunks.  Also, the spec must explain that (for performance reasons) the implementation may postpone the polling, but only for a bounded time.  An interrupt check must also be performed when the interrupt-level is set to 0, either due to a call (enable-interrupts!) or (current-interrupt-level 0) or on the way out of a binding done with (parameterize ((current-interrupt-level …)) …) or on the way in of a binding done with (parameterize ((current-interrupt-level 0)) …).
>
> The latter is, in general, too strict; as the body of parameterize is
> in tail context when parameterize is in tail context, every return
> from a call can effectively set the interrupt level to 0, meaning that
> interrupts would have to be polled at every return.

Not every return, just a return that returns to a continuation marked with a “parameterize”.  This is the (usual?) trick to avoid administrative overheads when returning to a special continuation (such as a continuation that is no longer on the stack).

>
>> The second comment is about the note “An interrupt can occur while a thread is blocked waiting on a condition variable”.  A thread can be interrupted in the “runnable” and “blocked” states, not just blocked on a condition variable (for example it could be blocked on a mutex, or sleeping).  The only situations where it can’t be interrupted is when the interrupt level is not 0, or when the state of the thread is “new” (i.e. created but not yet made runnable) and “terminated”.
>
> I called it a "note" precisely because it is not exhaustive.  I will
> expand the note so that there are no misunderstandings.
>
>> Finally, the current-interrupt-level mechanism may be too coarse.  Perhaps an interrupt level per interrupt source might be needed for some applications.  I think the current design is OK for now if current-interrupt-level is seen as a “global” interrupt masking machanism.  A future SRFI can add a mechanism that is more fine-grained.  I think this could be implemented on top of the interrupt mechanism of this SRFI.
>
> Having future SRFIs for, say, keyboard or timer interrupts makes sense.
>
> Ultimately, a timer would call thread-interrupt! but before, it would
> have to poll a timer-specific interrupt level parameter.  Do you have
> an idea how to make this polling efficient without further primitives?
>

My rough idea is that the timer interrupt would call thread-interrupt! unconditionnaly, and then the thunk (executed in the interrupted thread) would check the timer interrupt mask of that thread and if it is disabled, add the action to the end of a queue of actions to perform when timer interrupts are no longer masked.  If the timer interrupt mask is accessed with:

(enable-timer-interrupts!)
(disable-timer-interrupts!)

then it is easy to implement enable-timer-interrupts! as changing the interrupt mask and also checking for any pending actions.

A timer interrupt “level” mechanism is harder to implement because the “checking for any pending actions” needs to be done when the level goes back to 0 (possibly on the way out of a parameterize) and there’s no way to do this with parameter objects.  By the way this is also a problem with the current spec of current-interrupt-level.  It is important to have a garantee of checking for interrupts in this code:

(let loop ()
  (parameterize ((current-interrupt-level 1)) (set! count (+ count 1)))
  (loop)) ;; <-- interrupt checking not optional here otherwise thread will be uninterruptible

>> I’m slowed down by other things right now so I can’t yet comment on the rest of SRFI 226.
>
> Thank you for your valuable comments so far!
>
> I would like to get SRFI 226 finalized within the following weeks.

I feel like this SRFI deserves a longer review period… there’s so much stuff and relatively few reviewers.  In fact one suggestion would be to break it up into multiple SRFIs because some aspects are orthogonal (for example fluids, which I don’t particularly like for various reasons and in particular because they require identifier syntax that is not standard among implementations of Scheme).

Marc