How would you block in a software interrupt?

applefat wrote on Monday, February 26, 2018:

I realize that FreeRTOS documentation notes many many times that one should only use FromISR functions when in an interrupt context. Semantically I get that trying to make the “current task” block in an arbitrary asynchronous task like a timer interrupt, ADC interrupt, etc doesn’t make a lot of sense.

But what about software interupts–specifically SWI/SVC in ARM Cortex M4? Although it runs in interrupt context it is always treated like a function call. It’s fully synchronous to the currently executing task. And many OSes uses software interrupts to implement system calls, so its not outside the realm of what a user might need.

What guards would I need to make for a “FromSWI” version of, say vTaskDelay? Logically all a delay is is putting the task onto the delayed list and then doing a Yield.

(I know that FreeRTOS uses SVC 0. That itself is not a hurdle since one can check the immediate value in a handler).

rtel wrote on Monday, February 26, 2018:

All context switching is done in the PendSV handler, and if you are in
an SVC handler and pend the PendSV handler it is not going to run until
after the SVC handler has exited. Therefore you would need to introduce
a ‘yield from SVC function’ (which is effectively what the code does
when the first task is started, in the SVC 0 handler you mentioned
before). That would then probably require all yields to be performed
from an SVC handler - which is effectively what the old ARM7 port does
(ARM7 confusingly being an ARMv4 architecture, rather than the Cortex-M,
which is an ARMv7 architecture) - but would make yielding from
interrupts require assembly code entry and exit points (avoiding that is
probably possible but I would have to study it for a while to see how -
in any case, the resultant code would be a lot more complex).

What is the main objective of what you are trying to do? I have
compiled the kernel code as a separate binary that was ROMed into a chip
once, then user application code effectively linked with it using a
fixed jump table, rather than SVC calls.

heinbali01 wrote on Monday, February 26, 2018:

Hi Aaron,

In my opinion:
A software interrupt is just like a hardware interrupt, the handling code should be as short as possible.
Sometimes one sees a uS delay, which is implemented as a loop with NOP instructions. But calling a blocking function would be like committing suicide: no other task can run and so no-one can not unblock the task, once the vTaskDelay() has finished.
True that many OS’s use ‘software interrupts’ to implement systems calls. But these calls won’t do much more than scheduling a function that should answer the request.
Within FreeRTOS+TCP, the API’s were implemented by sending a message to a queue.

I suppose you’ve heard of “deferred interrupt handler”: it is a technique in which the ISR is kept extremely short. It will read a status, clear flags, and send (queue) a message to the appropriate handler.

applefat wrote on Monday, February 26, 2018:

Hi Richard, I’m a bit confused about what you are saying about the need to introduce a new yield function. It’s documented that you should use portYIELD_FROM_ISR at the end of ISRs, and in Cortex M4 this appears to boil down to the exact same portYIELD that is used from normal task context (e.g. portYIELD_WITHIN_API). So, since PendSV is given lowest priority it already seems to be the case that the PendSV is delayed until after whichever ISR it’s asserted in, and this is expected.

Or… is what you’re suggesting that the normal API calls actually rely on PendSV being synchronous/immediate?

In fact I was previously studying the jump table approach for linkage. It had just struck me that that SVC seemed like the more elegant approach because the caller doesn’t need to know anything about what’s on the other end, not even a jump table offset.

But if somebody had already gone that route and can say its a lot harder, that’s all I need to hear…

rtel wrote on Monday, February 26, 2018:

FreeRTOS is designed to allow both synchronous and asynchronous yields
(ARMv4 using synchronous and ARMv7 using asynchronous, for example) -
but these yields must happen either immediately for synchronous, or as
soon as a containing critical section is exited for asynchronous. Just
setting the PendSV from inside an SVC won’t achieve either of those -
the PendSV won’t execute until the SVC function returns.

richard_damon wrote on Tuesday, February 27, 2018:

One issue with a Software Interrupt is that, like a hardware interrupt, it is entered via a form of context switch, so you no longer are in the context for the calling task, so the software interrupt isn’t in a position to simply do actions on behalf of the software that called it. In order to block the calling task, you would need to get back to the context of that calling task, and then invoke the needed FreeRTOS functionality.