Question about taskYIELD()

dansear wrote on Friday, August 03, 2007:

In xQueueSend() (and xTaskResumeAll() and some others) there is a call to
taskYIELD() inside a taskENTER_CRITICAL()/taskEXIT_CRITICAL() section. In
our implementation interrupts are disabled inside the critical section, so
our tick interrupt won’t run. We’re running preemptive as well. Is there
any possible problems with getting tasks to switch, or losing ticks?

Dan Searles

rtel wrote on Friday, August 03, 2007:

It is the intended behaviour that the context switch occurs within the critical section - this allows the use of the scheduler locking mechanism.  Each task should maintain its own interrupt status.  Therefore a task that has interrupts disabled can call taskYIELD(), and switch to a task that may have interrupts enabled.  When the original task next runs it starts with the interrupts in the state in which it expects to find them - disabled.  Therefore this mechanism does not mean that interrupts remain disabled until the task executes again.

Regards.

barsuk1 wrote on Wednesday, March 12, 2008:

Hi there,
I’m trying to port FreeRTOS now to CEVA DSP and I have a question which seems to me to be a compliment to the above discussion:
In my understanding taskYield() should always be called from the critical section  since it actually performs context switch.
However in the code of the task.c there are places where taskYield() is called outside the portENTER_CRITICAL/portEXIT_CRITICAL macros. E.g. in the vTaskSuspend method, xTaskresumeAll and some other places.
Was this done intentionally ? If yes, what is the reason?

Thank you,
Igor.

rtel wrote on Wednesday, March 12, 2008:

taskYIELD() absolutely MUST be implemented so that it can be called either from within a critical section OR from outside of a critical section. 

If called from within a critical section then when the task that made the taskYIELD() call next runs it must re-start also from within the same critical section (with interrupts disabled).

If called from outside a critical section, then when the task that made the taskYIELD() call next runs it must re-start also from outside a critical section (with interrupt enabled).

Regards.

nestwave wrote on Tuesday, November 24, 2015:

Since taskYIELD can be called from outside critical section, and
since taskYIELD typically calls vTaskSwitchContext,
then vTaskSwitchContext may end up being called from outside critical section.

This appears to be the case in the GCC ATMega323 port, for example (cf. below).

Could you explain if it’s OK for vTaskSwitchContext to occur outside critical section?

Regards.

void vPortYield( void ) __attribute__ ( ( naked ) );
void vPortYield( void )
{
	portSAVE_CONTEXT();
	vTaskSwitchContext();
	portRESTORE_CONTEXT();

	asm volatile ( "ret" );
}

davedoors wrote on Tuesday, November 24, 2015:

This is a VERY old thread and VERY specific to the FreeRTOS port. In the AVR portSAVE_CONTEXT() disables interrupts so vTaskSwitchContext() is protected.

nestwave wrote on Tuesday, November 24, 2015:

OK, I see that interrupts are disabled at the beginning of portSAVE_CONTEXT (cli instruction, I guess).

So in general ports, interrupts should be (re)disabled around start of vPortYield, and not assume that they are already disabled?

rtel wrote on Tuesday, November 24, 2015:

Each port has a different mechanism for yielding to a different task,
and each case has to be considered on its own.

More often than not, yielding is done using a standard or software
interrupt, in which cases the hardware will either itself disable
interrupts on interrupt entry, or otherwise the interrupt priority
mechanism and/or asm code is used to manage interrupt nesting to ensure
the context switch can occur cleanly.

Also, some ports can/must yield in a critical section and the RTOS must
save/restore the critical section nesting as part of the task context,
while other ports (Cortex-M and RX for example) can’t possibly yield
from a critical section.

You are looking at a very basic port (as its a basic microcontroller),
in which yielding is performed using a function call, and in that case
interrupts are disabled manually. This is not really a critical section

  • the RTOS manages the yield, so is responsible for ensuring interrupts
    are left in the correct state when a task starts to run.