I realised that I was completely misunderstanding the use of the term “synchronous” in the description of the type InterruptState. I now believe that synchronous interrupts require co-operation from the thread being interrupted while asynchronous interrupts are pre-emptive (not the other way round). Have I got it right now?
The documentation says that asynchronous interrupts occur "at a suitable point soon after they are triggered”. Is iit possible to state what the suitable points are.
In any case, I think that my code (which is just trying to make a a call of a single-threaded function time out) should loop after sending the sending the interrupt waiting for the interrupted thread to become inactive. Does that sound right?
Regards,
Rob.
On 8/18/2025 11:51 AM, Rob Arthan wrote:
I realised that I was completely misunderstanding the use of the term “synchronous” in the description of the type InterruptState. I now believe that synchronous interrupts require co-operation from the thread being interrupted while asynchronous interrupts are pre-emptive (not the other way round). Have I got it right now?
The documentation says that asynchronous interrupts occur "at a suitable point soon after they are triggered”. Is iit possible to state what the suitable points are.
I can't speak for polyml specifically, but as a virtual machine designer / implementer I can say that designs are simpler and more robust if one uses vm-inserted checks for interrupts, done at places where the low level vm state is relative "clean". The goal is to limit the number of kinds of places while still keeping interrupt latency bounded and relatively low. A typical design would check at calls and/or returns and at loops (backward branches). The latter may manifest as tail calls in a number languages.
Exactly what the places are is a VM design choice, not a language design choice, so it is appropriate that it be a bit vague while perhaps stating the semantic guarantee (bounded time) and performance hope (generally short).
Note that bounded time pretty much requires a check in any loop whose number of iterations cannot be statically bounded. And since the stack is bounded, it is not absolutely necessary to check on ordinary (not tail) calls and returns, though doing so can reduce latency.
HTH -- Eliot Moss
On 18/08/2025 17:24, Eliot Moss wrote:
On 8/18/2025 11:51 AM, Rob Arthan wrote:
I realised that I was completely misunderstanding the use of the term “synchronous” in the description of the type InterruptState. I now believe that synchronous interrupts require co-operation from the thread being interrupted while asynchronous interrupts are pre-emptive (not the other way round). Have I got it right now?
The documentation says that asynchronous interrupts occur "at a suitable point soon after they are triggered”. Is iit possible to state what the suitable points are.
I can't speak for polyml specifically, but as a virtual machine designer / implementer I can say that designs are simpler and more robust if one uses vm-inserted checks for interrupts, done at places where the low level vm state is relative "clean". The goal is to limit the number of kinds of places while still keeping interrupt latency bounded and relatively low. A typical design would check at calls and/or returns and at loops (backward branches). The latter may manifest as tail calls in a number languages.
Exactly what the places are is a VM design choice, not a language design choice, so it is appropriate that it be a bit vague while perhaps stating the semantic guarantee (bounded time) and performance hope (generally short).
Yes. It actually uses a single check for stack overflow and for an interrupt. An interrupt causes the stack limit to be set to the start of the stack so the next check will cause the thread to call into the run-time system. Stack check code is inserted at the start of most functions and also in loops. However, there is no interlock between the thread that modifies the stack limit and the thread that is checking its stack. That means that there is some indeterminacy in how long it will take for the change to be seen, particularly on the ARM with its weak memory ordering.
Regards, David
On 18 Aug 2025, at 17:46, David Matthews David.Matthews@prolingua.co.uk wrote:
On 18/08/2025 17:24, Eliot Moss wrote:
On 8/18/2025 11:51 AM, Rob Arthan wrote:
I realised that I was completely misunderstanding the use of the term “synchronous” in the description of the type InterruptState. I now believe that synchronous interrupts require co-operation from the thread being interrupted while asynchronous interrupts are pre-emptive (not the other way round). Have I got it right now?
The documentation says that asynchronous interrupts occur "at a suitable point soon after they are triggered”. Is iit possible to state what the suitable points are.
I can't speak for polyml specifically, but as a virtual machine designer / implementer I can say that designs are simpler and more robust if one uses vm-inserted checks for interrupts, done at places where the low level vm state is relative "clean". The goal is to limit the number of kinds of places while still keeping interrupt latency bounded and relatively low. A typical design would check at calls and/or returns and at loops (backward branches). The latter may manifest as tail calls in a number languages. Exactly what the places are is a VM design choice, not a language design choice, so it is appropriate that it be a bit vague while perhaps stating the semantic guarantee (bounded time) and performance hope (generally short).
Yes. It actually uses a single check for stack overflow and for an interrupt. An interrupt causes the stack limit to be set to the start of the stack so the next check will cause the thread to call into the run-time system. Stack check code is inserted at the start of most functions and also in loops. However, there is no interlock between the thread that modifies the stack limit and the thread that is checking its stack. That means that there is some indeterminacy in how long it will take for the change to be seen, particularly on the ARM with its weak memory ordering.
Thanks, but you are both going a little bit fast for me here.
My understanding of the above is that:
(1) I was right that asynchronous interrupts are intended to be more pre-emptive than synchronous ones but that they aren’t hardware interrupts and are checked for in software when functions start or in loops. The function I am calling will be making function calls (but likely not RTS calls) all the time, so this is as close to pre-emptive behaviour as I need.
(2) I also asked:
In any case, I think that my code (which is just trying to make a a call of a single-threaded function time out) should loop after sending the sending the interrupt waiting for the interrupted thread to become inactive. Does that sound right?
And, from what you have said, I think my code should indeed wait for the interrupted thread to become inactive rather than return immediately after sending the interrupt.
Regards,
Rob.