uxTopReadyPriority updated from ISR while switching task

Hello everyone, we are currently using FreeRTOS on a Blackfin processor and facing an issue when releasing a high-priority task from ISR. We may have made a mistake during porting but are unable to find where. I found several topics linked to this issue (uxTopReadyPriority variable in particular) but still do not understand the problem. We have the following config : configUSEPREEMPTION = 1 configUSEPORTOPTIMISEDTASK_SELECTION = 0 We have sereral tasks running at low priority (3) and one task running at higher priority (5). In the context switching interrupt subroutine (lowest IRQ priority), we call vTaskSwitchContext after enabling interrupts again, thus taskSELECTHIGHESTPRIORITY_TASK is called with interrupts on. What we see While we are in vTaskSwitchContext, we enter taskSELECTHIGHESTPRIORITY_TASK. At that time, the high-priority task is asleep and uxTopReadyPriority=3. uxTopPriority is loaded with this value. At that point, an IRQ is triggered (priority higher than task switching ISR but lower than configMAXSYSCALLINTERRUPTPRIORITY) and it calls syssemaphorereleaseISR to release the high-priority task. syssemaphorereleaseISR calls xQueueGiveFromISR -> xTaskRemoveFromEventList -> prvAddTaskToReadyList -> taskRECORDREADY_PRIORITY and finally uxTopReadyPriority is set to 5. When we are back in the context switching subroutine, we are still in taskSELECTHIGHESTPRIORITY_TASK and have uxTopPriority=3. We run the “uxTopReadyPriority = uxTopPriority;” command, that sets uxTopReadyPriority to 3 back again. As a result, the high-priority task will never be executed. Thus, did we made a mistake with our interrupt priorities ? Is it a normal bahaviour that a task can call FromISR functions while the task switching interrupt is in taskSELECTHIGHESTPRIORITY_TASK ? Task switching interrupt | Other interrupt ———- | ———- vTaskSwitchContext |
taskSELECTHIGHESTPRIORITYTASK | *UBaseTypet uxTopPriority = uxTopReadyPriority*; | syssemaphorereleaseISR | xQueueGiveFromISR | xTaskRemoveFromEventList |prvAddTaskToReadyList | taskRECORDREADYPRIORITY | *uxTopReadyPriority=5* while( listLISTIS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) | … | *uxTopReadyPriority = uxTopPriority*; | Thanks for any comment that would help us understand how this should work. Romain

uxTopReadyPriority updated from ISR while switching task

Hi – first to point out that we don’t provide a Blackfin port ourselves, so we don’t know how the port is implemented. However…
In the context switching interrupt subroutine (lowest IRQ priority), we > call vTaskSwitchContext after enabling interrupts again, thus > taskSELECTHIGHESTPRIORITYTASK is called with interrupts on. …if the port supports interrupt nesting then that sounds wrong. Interrupts should be masked either completely, or up to configMAXSYSCALLINTERRUPTPRIORITY when vTaskSwitchContext() is called.
Does the port support interrupt nesting? It sounds like it does if variables in vTaskSwitchContext() change while it is being executed (implying it has been re-entered somewhere). If you only see this when stepping through code in the debugger then another possibility could be that the debugger is enabling interrupts between steps.

uxTopReadyPriority updated from ISR while switching task

Thanks for your answer Richard. Indeed the port supports interrupt nesting. The problem appears not only when using debugger but also when running “normally”, so the debugger is not to blame. Thus, if I understand well, vTaskSwitchContext has to be called from a critical section if interrupt nesting is enabled ? We may have missed this point… On the other hand, we tried to have a better understanding by reading the Cortex-a9 port, and vTaskSwitchContext is called from the SWI handler, which can be interrupted by the IRQ handler. So we did not find what prevents FromISR functions calls from an ISR while taskSELECTHIGHESTPRIORITY_TASK is running in the SWI handler.

uxTopReadyPriority updated from ISR while switching task

I think, without checking ;o) that the Cortex-A9 calls the ISR with interrupt disabled, and because they are not re-enabled, vTaskSwitchContext() executes without the risk of itself being interrupted. The Cortex-A ports have a single interrupt entry point, and some people prefer to enable interrupts there, before [manually] vectoring to the actual interrupting peripheral. Others prefer to leave interrupts disabled there, and only selectively re-enable interrupts (to allow nesting) inside the individual interrupt handlers. On the Cortex-M parts the PendSV interrupt is used for context switching. If you look at the handler you will see interrupts being masked up to the configMAXSYSCALLINTERRUPTPRIORITY (not globally masked) by a write to the basepri register immediately before calling vTaskSwitchContext(). At the time of writing this can be seen on line 406 on the following link: https://sourceforge.net/p/freertos/code/HEAD/tree/trunk/FreeRTOS/Source/portable/GCC/ARMCM3/port.c

uxTopReadyPriority updated from ISR while switching task

I read the code from the Cotex-M and it seems clear to me. I understand that there is no conflict when accessing the uxTopReadyPriority variable has low priority interrupts are off when we are in vTaskSwitchContext. But if I’m right, the Cortex-A9 port we looked at is a bit different and closer to our code. The SWI handler (task switch) is not called from the interrupt entry point but from the SVC entry point, which has a lower priority than IRQs and can be interrupted by them (code is located in portable/RVDS/ARM_CA9). However, it seems that an optimized version of task selection replaces the default one, #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __clz( uxReadyPriorities ) ) This code does not overwrite the topPriority variable in portGETHIGHESTPRIORITY and the release of the high priority task is not masked. Using a aquivalent code for our port seems to solve our issue (without border effects I hope). Could it be that the default task selection code shall not be used when vTaskSwitchContext may be interrupted, whereas this optimized version can be ?

uxTopReadyPriority updated from ISR while switching task

The code you show above is for when configUSEPORTOPTIMISEDTASKSELECTION is set to 1. If you use that code you must also set that constant as it changes the way priorities are tracked from a simple integer to a bitmap (hence the use of the CLZ instruction, using a single ASM instruction to find the highest priority). Careful in your comparison with the A9 port as different processors work in very different ways. I think you will find that SVC disables interrupts before entering the handler, and if interrupts are not re-enabled in the handler (again, I’ve not actually checked) then interrupts remain disabled during the task selection.

uxTopReadyPriority updated from ISR while switching task

We finally disabled all interrupts before entering vTaskSwitchContext to avoid any problem. Thanks for your help.