Can a Switch to another task occur between the call "taskENTER_CRITICAL" and "taskEXIT_CRITICAL"?

tugouxp wrote on Thursday, August 22, 2019:

In the White paper 161204_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide, page 265, it says:
/* A switch to another task cannot occur between the call to taskENTER_CRITICAL() and
the call to taskEXIT_CRITICAL(). Interrupts may still execute on FreeRTOS ports that
allow interrupt nesting, but only interrupts whose logical priority is above the
value assigned to the configMAX_SYSCALL_INTERRUPT_PRIORITY constant – and those
interrupts are not permitted to call FreeRTOS API functions. */
PORTA |= 0x01;

But, Frome the Code xQueueGenericReset, it shows that
“queueYIELD_IF_USING_PREEMPTION” was invoked between “taskENTER_CRITICAL()” and “taskEXIT_CRITICAL()”
So, How to comprehensive this two conflicts? As reading from the code, i believe it is safe to volunter yield to another task. but the tow conflicts exists, which supporsed to be right?

rtel wrote on Thursday, August 22, 2019:

It depends on the kernel port. Assuming you are using a port that supports interrupt nesting then requesting a context switch inside a critical section will result in the switch being held pending until the critical section is exited - then when interrupts are re-enabled the pending context switch interrupt executes.

tugouxp wrote on Thursday, August 22, 2019:

that maybe work flow on cortex-m series, which support pendsv press under in interrupt context.
but such as on CA9, the volunteer yield operation is done through “svc” call, which would step into svc flow directely and do the swich at once, i did not see any condition would block this switch,
it seems the swith would happed and success on CA9 port., which meas voluteer yiled could be done in “taskENTER_xxxx” and “taskEXIT_xxxx” region.

may be i am wrong, but if let me know where i am, it woud be greateful to you!
thank you.

rtel wrote on Thursday, August 22, 2019:

You are right, which is why I say it depends on the port. In the A9 case the context switch interrupt is synchronous and the kernel code itself is constructed to allow this within API functions - but application code should not perform a context switch inside a critical section and will most likely hit an assert() if they do.

tugouxp wrote on Thursday, August 22, 2019:

Thanks for your kindly clarification, and i learn this.

richard_damon wrote on Thursday, August 22, 2019:

My understanding is as a general principle, you should not invoke FreeRTOS operations within a critical section. It may work for some functions on some ports, but in general it should be avoided.

My personal guidelines are that critical section should be kept VERY short, you enter the section, do a few quick operations on globals that need to be done atomically, and then exit the critical section. As a quick guideline, if it is going to need to execute over 100 assembly instructions (and even that is somewhat high) thing strongly if you need this type of critical section. That rule tends to disallow calling most FreeRTOS functions. You only really need taskENTER_CRITICAL/taskEXIT_CRITICAL if you need to protect the operation from an interrupt. It can be used to protect from other tasks, but for that purpose other methods work, and the reason to use taskENTER_CRITICAL there is that it is short so the lower overhead makes sense.

FreeRTOS internally seems to use a similar guideline, although I think there the term is more it must be bounded time.

Longer protected regions if only needing to protect from tasks could use vTaskSuspendAll()/vTaskResumeAll() or a mutex to provide the interlock, preference being based on the type of interactions.

Longer protected regions that need to block a particular interrupt, will use a vTaskSuspendAll() with a disable of that particular interrupt.

Longer protected regions that need to block many/all interrupt, tend to cause a serious look at the architecture to see if there is a better way to do it.