Select Page

RESOURCE

INTRODUCTION EXAMPLE ASSIGNMENTS

Resource Management

Resources that are shared between tasks or between tasks and interrupts needs to be managed using a ‘mutual exclusion’ technique to ensure data consistency.

Basic Critical Sections

  • Basic critical sections protect a region of code from access by other tasks and by interrupts
    Regions of code that are surrounded by calls to the macros taskENTER_CRITICAL() and taskEXIT_CRITICAL() respectively,
   /* Ensure access to the PORTA register cannot be interrupted by placing it with in a critical section. */
   taskENTER_CRITICAL();
 
   /* 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 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;
 
    /* We have finished accessing PORTA so can safely leave the critical section */
    taskEXIT_CRITICAL();
  • A very crude method of providing mutual exclusion as all or partial interrupts are disabled

Suspending (Locking) the Scheduler

  • Critical sections can also be created by suspending the scheduler
  • A critical section that is too long to be implemented by simply disabling interrupts can instead be implemented by suspending the scheduler
  • The scheduler is suspended by calling vTaskSuspendAll()
void vTaskSuspendAll( void );

The scheduler is resumed by calling xTaskResumeAll()

portBASE_TYPE xTaskResumeAll( void );

Mutexes

  • A Mutex is a special type of binary semaphore that is used to control access to a resource that is shared between two or more tasks
  • The mutex can be conceptually thought of as a token associated with the resource being shared
  • For a task to legitimately access the resource it must first successfully ‘take’ the token
  • When the token holder has finished with the resource it must ‘give’ the token back.

Create a Mutex

Use xSemaphoreCreateMutex() to create a mutex

xSemaphoreHandle xSemaphoreCreateMutex( void );

Priority Inversion & Priority Inheritance

  • With a mutex, it is possible that a task with a higher priority has to wait for a task with a lower priority which hold the mutex to give up the control of the mutex
  • A higher priority task being delayed by a lower priority task in this manner is called ‘priority inversion’.
  • Priority inheritance works by temporarily raising the priority of the mutex holder to that of the highest priority task that is attempting to obtain the same mutex
  • The priority of the mutex holder is automatically reset back to its original value when it gives the mutex back
  • Priority inheritance does not ‘fix’ priority inversion, it merely lessens its impact.

Deadlock

Deadlock occurs when two tasks are both waiting for a resource that is held by the other, e.g.,

  1. Task A executes and successfully takes mutex X.
  2. Task A is pre-empted by Task B.
  3. Task B successfully takes mutex Y before attempting to also take mutex X – but mutex X is held by Task A so is not available to Task B. Task B opts to enter the Blocked state to wait for mutex X to be released.
  4. Task A continues executing. It attempts to take mutex Y – but mutex Y is held by Task B so is not available to Task A. Task A opts to enter the Blocked state to wait for mutex Y to be released.

Gatekeeper Tasks

  • Gatekeeper tasks provide a clean method of implementing mutual exclusion without the worry of priority inversion or deadlock
  • A gatekeeper task is a task that has sole ownership of a resource
  • A task needing to access the resource can only do so indirectly by using the services of the gatekeeper