How would you block in a software interrupt?

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

How would you block in a software interrupt?

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.

How would you block in a software interrupt?

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.

How would you block in a software interrupt?

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 portYIELDFROMISR 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. portYIELDWITHINAPI). 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…

How would you block in a software interrupt?

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.

How would you block in a software interrupt?

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.