Available Languages?:

This is an old revision of the document!


OSA : Critical sections

Intro

Critical sections are used to provide task with some resource inseparably when this resource is used by other tasks. For example some task works with EEPROM and entered critical section to avoid EEPROM data modifiation by other tasks.

In fact, this is rare situation for cooperative RTOS because the programmer switchs context manualy, but still this is possible. So OSA have services to protect critical sections of program.

To aviable work woth critical sections you must to define OS_ENABLE_CRITICAL_SECTION constant in OSAcfg.h.

There are two services to protect program's critical sections:

When entering critical section, all interrupts are disabled (their current value stored in internal system flags). Only one task who called service OS_EnterCriticalSection can get control independent of priority, and all other tasks will be blocked until OS_LeaveCriticalSection will be called. When in critical section it still possible to return to schdeuler.

To work with critical sections you need to know some rules written below

GIEx saving

Service OS_EnterCriticaSection saves current GIEx values, and after saving these flags will be cleared. Thus if you call this service twice at one time, then saved GIEx's value at first call will be overwritten with zeroes at second call since after first call GIEx have been cleared. OS_LeaveCriticalSection in this situation will restore zeroed GIEx saved at second call.

Avoid calling service OS_EnterCriticalSection twice at one time.

Timers

You will be able to use task delays (OS_Delay) and waiting with timeout services only if OS_Timer is called not from interrupt (since interrupts are disabled while in critical section). There are two wais of solving this problem:

  1. To enable interrupts manualy after entering critical section (if program architecture allows to use interrupts while in critical section)
  2. To dublicate call of OS_Timer in main cycle (near OS_Sched). See example below:
void interrupt int_routine (void)
{
    OS_EnterInt();
    if (TMR2IF)       // This code will not work in critical section
    {
         TMR2IF = 0;
         OS_Timer();  // This service will be called only outside critical section
    }
    OS_LeaveInt();
}
 
void Task1 (void)
{
    for (;;) {
        . . .
        OS_EnterCriticalSection();
        OS_Delay(100);
        OS_LeaveCriticalSection();
        . . .
    }
}
 
void main (void)
{
    OS_Init();
    OS_Task_Create(0, Task1);
    for (;;)
    {
        OS_Sched();
        if (OS_IsInCriticalSection()) {
            if (TMR2IF) {
                TMR2IF = 0;
                OS_Timer();    // This service will be called within critical section
            }
        }
    }
}

Wait for events

All task except one (who called OS_EnterCriticalSection) are blocked even if their priority is highest and they are ready to run. Thus if task enters critical section and then waits for event that occures in other task, then system will be looped. To avoid this you can first awaiting an event and then enter critical section.

void Task1 (void)
{
    for (;;) {
        . . .
        // Incorrect
        OS_EnterCriticalSection();
        OS_Bsem_Wait(BS_USART_FREE);
        . . .
        // Correct
        OS_Bsem_Wait(BS_USART_FREE);
        OS_EnterCriticalSection();
        . . .
    }
}

Services

Service Arguments Description Properties
bool
OS_IsInCriticalSection
Return true if one of task is in critical section
OS_EnterCriticalSection Enter critical section Allowed only in task
OS_LeaveCriticalSection Leave critical section Allowed only in task
 
en/osa/ref/services/critical_sections.1260572375.txt.gz · Last modified: 12.12.2009 01:59 by osa_chief
 
Creative Commons License Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki