Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT




Loading

taskYIELD() in critical section

Posted by Grigore-Mihai Dobra on March 19, 2009
In freeRTOS 5.1.12, there is a taskYIELD() inside a critical section(portENTER_CRITICAL) in function xTaskResumeAll. Is that ok? If disabling the interrupts before switching the context, who will preempt the new running task?

RE: taskYIELD() in critical section

Posted by Richard on March 19, 2009
I really need to add this to the FAQ!

Yes this is perfectly OK everywhere the scheduler does it, although i don't recommend doing this in the application code unless you fully understand the consequences.

Each task maintains its own flags value so a task can yield from a critical section to a task that is not in a critical section - the original idea being that when the original task started to run again it would start from within a critical section and therefore have guaranteed access to the data structures. This reason has actually since disappeared but it is still safe.

Regards.

RE: taskYIELD() in critical section

Posted by Grigore-Mihai Dobra on March 19, 2009
Maybe I'm missing the point here, but when you enter a critical section, uxCriticalNesting is incremented and the interrupts are disabled. The interrupts being disabled, no timer interrupt will give the kernel the tick. This means the current task(the one becoming active after yield) will run for an indefinite amount of time without being preempted.

RE: taskYIELD() in critical section

Posted by Richard Damon on March 20, 2009
What you are missing is that as part of the context switch caused by the yield will re-enable the interrupts (unless the new task was also in a critical section) as uxCriticalNesting is stored on a per TASK basis.

RE: taskYIELD() in critical section

Posted by Grigore-Mihai Dobra on March 20, 2009
Well, first, I should say that my architecture won't store the General Interrupt Flag in the Program Status Word, thus this flag will not be saved/restored at a context switch.

More, nowhere in the example ports did I see that uxCriticalNesting is stored on a per task basis. Could this feature be introduced later from the V5.1.2 or so?

So I am still puzzled by this yield inside critical section.

RE: taskYIELD() in critical section

Posted by Grigore-Mihai Dobra on March 20, 2009
Ok, it is clear to me now, as I have inspected 'tasks.c' and found this:
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
unsigned portBASE_TYPE uxCriticalNesting;
#endif

So I'll just have to redesign a little my context switch functions(timer interrupt and yield 'function') to use this feature.

RE: taskYIELD() in critical section

Posted by Richard on March 20, 2009
In most cases the critical nesting count is stored on the stack of the task, but in newer ports it is stored as part of the TCB.

Also, not wanting to add confusion to the discussion, but some ports now don't actually yield until they leave the critical section. This part is very port specific.

Regards.

RE: taskYIELD() in critical section

Posted by Grigore-Mihai Dobra on March 20, 2009
As I have already said in a missposted post: https://sourceforge.net/forum/message.php?msg_id=6885683

RE: taskYIELD() in critical section

Posted by Richard on March 20, 2009
If you have the nesting count then you don't need the status word as well, just look at the nesting count value to know if you are in a critical section or not.

Which architecture are you using?

Regards.

RE: taskYIELD() in critical section

Posted by Grigore-Mihai Dobra on March 22, 2009
Well, I am trying to port freeRTOS to NXP 51XA(8051 eXtended Architecture). Upon interrupt, the stack contains the PSW(program status word), PC(program counter), and eventually, the CS(Code segment), if using the non-page zero mode. Non-page zero mode means the controller will use more than 64KB of RAM and more that 64KB of code. I won't go into much detail here, just for reference.

Anyway, if using the uxCriticalNesting inside the TCB, another problem arises: Who will set the member variable uxCriticalNesting to 0? Because, if it is not set to zero, the start count will not be consistent with the interrupts enable/disable state.

RE: taskYIELD() in critical section

Posted by Prithwee on March 23, 2009
>>Who will set the member variable uxCriticalNesting to 0?

if you have set "portCRITICAL_NESTING_IN_TCB==1" then in tasks.c file, "prvInitialiseTCBVariables" function will take care of it.

RE: taskYIELD() in critical section

Posted by Grigore-Mihai Dobra on March 23, 2009
Yeah, that's right. Looked for something like this in the source code before asking the question, but found nothing. Looked again now, it's there. I should concentrate my attention better.

RE: taskYIELD() in critical section

Posted by Grigore-Mihai Dobra on March 28, 2009
Another problem found in xTaskCreate:

portENTER_CRITICAL();
{
uxCurrentNumberOfTasks++;
if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
{
/* As this is the first task it must also be the current task. */
pxCurrentTCB = pxNewTCB;

well, my implementation of portENTER_CRITICAL() is on a per-task basis(portCRITICAL_NESTING_IN_TCB == 1), so uxCriticalNesting is contained within the TCB. Well, pxCurrentTCB is not initialized at the point portENTER_CRITICAL() is called here. So my implementation of portENTER_CRITICAL() will alter some RAM zone which is not a TCB.

I saw in the source code that there are two forms of entering critical: portENTER_CRITICAL and taskENTER_CRITICAL. Unfortunately, both refer to the same function/code snippet. Why not split them to have one of them(taskENTER_CRITICAL) for tasks(TCB based) and the other(portENTER_CRITICAL) for the whole system(global uxCriticalNesting)?

Of course, my implementation of portENTER_CRITICAL could use both a global variable or the field from TCB, based on the scheduler state, but that would increase code size and timing.

RE: taskYIELD() in critical section

Posted by Richard on March 28, 2009
The idea is (was) that user code does not call anything in the port layer directly, only the task and queue API. Therefore user code should call taskENTER_CRITICAL() not portENTER_CRITICAL(), although the two are mapped to the same code so in reality it makes no difference unless you switch code from one port to another.

When portCRITICAL_NESTING_IN_TCB is set to 1 then the enter/exit critical section macros should map to vTaskEnterCritical() and vTaskExitCritical() [defined in task.c]. These functions will only attempt to access pxCurrentTCB if the scheduler is running to remove the risk of them accessing it before it have been set to point to a valid TCB structure.

Regards.

RE: taskYIELD() in critical section

Posted by Grigore-Mihai Dobra on March 28, 2009
Ok, I can see a valid critical section schema now. The truth is I haven't went on a exhaustive reading of the documentation or source code, so my questions could seem stupid sometimes.


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

FreeRTOS kernel V10 is available for immediate download. Now MIT licensed.


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS