6
\$\begingroup\$

In some RT kernels, if you want to post to a semaphore or flag from an ISR, you need to call an special version of the method, instead of the regular one called from a normal task. Examples:

However there are other kernels where this is not needed. For instance:

  • OSSemPost() in uC/OS can be called both from tasks and ISRs.
  • release() in mbed-rtos, can be called from Threads and ISRs.
  • semGive() in VxWorks seems to be callable from an ISR according to the docs, and at first glance no special method exists for ISRs.

Why would you need to create special versions? I understand that the posting of a semaphore or flag might cause a blocked task of higher priority to be awaken. And that's why the scheduler is most likely going to run when the ISR exit callback is called (I'm talking about those functions needed to be called when you want to use kernel code inside the ISR, like portEXIT_SWITCHING_ISR() in FreeRTOS, or OSIntExit in uC/OS). So why the special post method in addition to the ISRexit call?

\$\endgroup\$

2 Answers 2

7
\$\begingroup\$

I've been reading the source code of both FreeRTOS and CoOS.

In FreeRTOS (the port I found first in Google), the xSemaphoreGiveFromISR() function calls to xQueueGenericSendFromISR(), and this function had this comment:

/* Similar to xQueueGenericSend, except we don't block if there is no room
    in the queue.  Also we don't directly wake a task that was blocked on a
    queue read, instead we return a flag to say whether a context switch is
    required or not (i.e. has a task with a higher priority than us been woken
    by this post). */

As for CoOS, the function isr_PostSem called from an ISR just enqueues a request to the so called "Service request queue", using the function InsertInSRQ. I have no idea about what this queue is, probably is some system task to offload work from ISRs and thus let interrupts complete quickly.

As for mbed, which only has 1 version of the method, it is based on CMSIS RTOS, and there's a call to the function osSemaphoreRelease(). There's a comment about this and similar functions:

The following CMSIS-RTOS functions can be called from threads and interrupt
service routines (ISR):
  - osSignalSet
  - osSemaphoreRelease
  - osPoolAlloc, osPoolCAlloc, osPoolFree
  - osMessagePut, osMessageGet
  - osMailAlloc, osMailCAlloc, osMailGet, osMailPut, osMailFree

Functions that cannot be called from an ISR are verifying the interrupt
status and return in case that they are called from an ISR context the status
code osErrorISR. In some implementations this condition might be caught using
the HARD FAULT vector.

So it seems to be just kernel design, some designers chose to have separate functions and let the programmer make the distinction, and some others prefered to have just one method and internally check if the call was made from an ISR.

\$\endgroup\$
1
  • \$\begingroup\$ +1 for actually finding the source and the comments that explain what the difference is and why! \$\endgroup\$
    – pjc50
    Jan 9, 2015 at 17:00
5
\$\begingroup\$

On many smaller microcontroller architectures, there is no true data stack for automatic variables. Instead, such variables are allocated statically, using an analysis function that takes into account the entire "tree" of function calls in order to make sure that (most of) the functionality of a stack is preserved.

On implication of this is that individual functions cannot be reentrant, at least, not without a lot of overhead. If you tried to call a function from within an ISR, you could be interrupting the same function that had been called from the mainline code. Essentially, each ISR has its own "tree" of function calls (usually a very small tree), and all such trees need to be physically distinct in terms of the data RAM that they use.

Therefore, each function must be assigned to one tree or the other, and you need separate copies of functions that might be called from multiple trees.

I think that you'll find that RTOS implementations that have separate functions are targeted to those smaller processor architectures, while those that don't are targeted entirely at architectures that have true data stacks.

\$\endgroup\$
2
  • \$\begingroup\$ Good point, but I don't think this is the issue, since most RTOS are aimed for 32 bit microcontrollers. I can't tell about some FreeRTOS ports, but I'm sure I've called recursive functions on CoOS (until I ran out of stack lol). \$\endgroup\$ Jan 9, 2015 at 16:29
  • \$\begingroup\$ "Most" is not "all". I know that some of those RTOS have ports to 8-bit PICs and 8051s, which are two example architectures that don't have true data stacks. You might have been using CoOS on an architecture (and compiler) that did not have this restriction. \$\endgroup\$
    – Dave Tweed
    Jan 9, 2015 at 16:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.