Inter-Task Communication

group OS_87x3e_Synchronization

Manage Inter-task communication functions.

Tasks need to communicate with each other or access shared resources together. There are many ways to exchange data between tasks, for example using shared data, polling loops and message passing.

Many resources can be considered as serially-reusable. This means that they can be used repeatedly by different tasks, but only by one task at a time.

The following mechanisms are available to the user:
  • Lock

  • Semaphore

  • Mutex

Variables

uint32_t (*os_lock)(void)

Enter the critical region. Disable preemptive context switch and interrupts.

os_sync.h

Example usage

int test(void)
{
    uint32_t s;

    // Enter the critical section.
    s = os_lock();
    // Allow only one task or ISR to operate the list.
    list_add(p_list, &item);
    // Exit the critical section and restore ISR mask flag.
    os_unlock(s);
}

Param None.:

Return:

Interrupt mask flag.

void (*os_unlock)(uint32_t s)

Exit the critical region. Enable preemptive context switch and interrupts.

os_sync.h

Example usage

int test(void)
{
    uint32_t s;

    // Enter the critical section.
    s = os_lock();
    // Allow only one task or ISR to operate the list.
    list_add(p_list, &item);
    // Exit the critical section and restore ISR mask flag.
    os_unlock(s);
}

Param s:

Interrupt mask flag to be restored.

Return:

None.

bool (*os_sem_create)(void **pp_handle, const char *p_name, uint32_t init_count, uint32_t max_count)

Create a counting semaphore.

os_sync.h

Semaphores are used to manage and protect access to shared resources. A semaphore can be used to permit a fixed number of task to access a pool of shared resources. Using semaphores.

A semaphore object should be initialized to the maximum number of available tokens. This number of available resources is specified as parameter of the

os_sem_create() function. Each time a semaphore token is obtained with os_sem_take(), the semaphore count is decremented. When the semaphore count is 0, no semaphore token can be obtained. The task that tries to obtain the semaphore token needs to wait until the next token is free. Semaphores are released with os_sem_give() incrementing the semaphore count.

../../_images/OS-semaphore-overview.jpg

Example usage

int test(void)
{
    void *p_handle;

    // Create a semaphore with initial value 0 and maximum value 10.
    if (os_sem_create(&p_handle, "sem name", 0, 10) == true)
    {
        // Semaphore created successfully.
    }
    else
    {
        // Semaphore failed to create.
        return -1;
    }

    return 0;
}

Param pp_handle:

Used to pass back the created semaphore handle.

Param p_name:

A descriptive name for the semaphore.

Param init_count:

The count value assigned to the semaphore when created.

Param max_count:

The maximum count value that can be reached. If the max_count is 1, a binary semaphore is being created.

Retval true:

Semaphore was created successfully.

Retval false:

Semaphore was failed to create.

Return:

The status of the semaphore creation.

bool (*os_sem_delete)(void *p_handle)

Delete a semaphore.

os_sync.h

Example usage

int test(void)
{
    void *p_handle;

    // Create a semaphore with initial value 0 and maximum value 10.
    if (os_sem_create(&p_handle, "sem name", 0, 10) == true)
    {
        // Semaphore created successfully.
    }
    else
    {
        // Semaphore failed to create.
        return -1;
    }

    // Delete the created semaphore.
    os_sem_delete(p_handle);

    return 0;
}

Param p_handle:

The handle of the semaphore to be deleted.

Retval true:

Semaphore was deleted successfully.

Retval false:

Semaphore was failed to delete.

Return:

The status of the semaphore deletion.

bool (*os_sem_take)(void *p_handle, uint32_t wait_ms)

Take a semaphore.

os_sync.h

Example usage

void *p_handle = NULL;

// One task creates a semaphore.
void task1(void *p_param)
{
    // Create a full binary semaphore.
    os_sem_create(&p_handle, "sem name", 1, 1);
}

// Anohter task uses the semaphore.
void task2(void *p_param)
{
    // See if we can obtain the semaphore. If the semaphore is
    // not available, wait for 100ms.
    if (os_sem_take(p_handle, 100) == true)
    {
        // Access the share resource.

        // Finish accessing the share resource, then release the semaphore.
        os_sem_give(p_handle);
    }
    else
    {
        // Could not access the share resource.
    }
}

Param p_handle:

The handle of the semaphore to be taken.

Param wait_ms:

The time in milliseconds to wait for the semaphore to become available.

  • 0 No blocking and return immediately.

  • 0xFFFFFFFF Block infinitely until the semaphore taken.

  • others The timeout value in milliseconds.

Retval true:

Semaphore was taken successfully.

Retval false:

Semaphore was failed to take.

Return:

The status of the semaphore taking.

bool (*os_sem_give)(void *p_handle)

Give a semaphore.

os_sync.h

Example usage

int test(void)
{
    void *p_handle = NULL;

    // Create an empty binary semaphore.
    os_sem_create(&p_handle, "sem name", 0, 1);

    // Obtaining the empty semaphore immediately will be failed.
    if (os_sem_take(p_handle, 0) == false)
    {
        // Failed.
    }

    // Give the sempahore
    if (os_sem_give(p_hanel) == true)
    {
        // Now we can take the semaphore.
        os_sem_take(p_handle, 0);

        // Again taking the binary semaphore will be failed.
        os_sem_take(p_handle, 0);
    }
}

Param p_handle:

The handle of the semaphore to be given.

Retval true:

Semaphore was given successfully.

Retval false:

Semaphore was failed to give.

Return:

The status of the semaphore giving.

bool (*os_mutex_create)(void **pp_handle)

Create a mutex.

os_sync.h

Mutex (Mutual Exclusion) is used to protect a shared resource that can be accessed only by one task at a time.

A mutex is a special version of a binary empty semaphore. The advantage of a mutex is that it introduces task ownership. When a task acquires a mutex and becomes its owner, subsequent mutex acquires from that task will succeed immediately. Thus, mutex acquires/releases can be nested.

../../_images/OS-mutex-overview.jpg

Example usage

int test(void)
{
    void *p_handle = NULL;

    // Create a mutex.
    if (os_mutex_create(&p_handle) == true)
    {
        // The mutex created successfully.
        // Now it can be used.
    }
}

Param pp_handle:

Used to pass back the created mutex handle.

Retval true:

Mutex was created successfully.

Retval false:

Mutex was failed to create.

Return:

The status of the mutex creation.

bool (*os_mutex_delete)(void *p_handle)

Delete a mutex.

os_sync.h

Example usage

int test(void)
{
    void *p_handle;

    // Create a mutex.
    if (os_mutex_create(&p_handle) == true)
    {
        // Mutex created successfully.
    }
    else
    {
        // Mutex failed to create.
        return -1;
    }

    // Delete the created mutex.
    os_mutex_delete(p_handle);

    return 0;
}

Param p_handle:

The handle of the mutex to be deleted.

Retval true:

Mutex was deleted successfully.

Retval false:

Mutex was failed to delete.

Return:

The status of the Mutex deletion.

bool (*os_mutex_take)(void *p_handle, uint32_t wait_ms)

Take a mutex.

os_sync.h

Example usage

void *p_handle = NULL;

// One task creates a mutex.
void task1(void *p_param)
{
    // Create a mutex.
    os_mutex_create(&p_handle);
}

// Anohter task uses the mutex.
void task2(void *p_param)
{
    // See if we can obtain the mutex. If the mutex is
    // not available, wait for 100ms.
    if (os_mutex_take(p_handle, 100) == true)
    {
        // Access the share resource.

        // In real code, recursive calls of mutex may occur.
        os_mutex_take(p_handle, 100);
        os_mutex_take(p_handle, 200);

        // The mutex has now been 'taken' three times, so will not be
        // available to another task until it has also been given back
        // three times.
        os_mutex_give(p_handle);
        os_mutex_give(p_handle);
        os_mutex_give(p_handle);

        // Finish accessing the share resource, then release the semaphore.
        // Now the mutex can be taken by other tasks.
    }
    else
    {
        // Could not access the share resource.
    }
}

Param p_handle:

The handle of the mutex to be taken.

Param wait_ms:

The time in milliseconds to wait for the mutex to become available.

  • 0 No blocking and return immediately.

  • 0xFFFFFFFF Block infinitely until the mutex taken.

  • others The timeout value in milliseconds.

Retval true:

Mutex was taken successfully.

Retval false:

Mutex was failed to take.

Return:

The status of the mutex taking.

bool (*os_mutex_give)(void *p_handle)

Give a mutex.

os_sync.h

Example usage

void *p_handle = NULL;

// One task creates a mutex.
void task1(void *p_param)
{
    // Create a mutex.
    os_mutex_create(&p_handle);
}

// Anohter task uses the mutex.
void task2(void *p_param)
{
    // See if we can obtain the mutex. If the mutex is
    // not available, wait for 100ms.
    if (os_mutex_take(p_handle, 100) == true)
    {
        // Access the share resource.

        // In real code, recursive calls of mutex may occur.
        os_mutex_take(p_handle, 100);
        os_mutex_take(p_handle, 200);

        // The mutex has now been 'taken' three times, so will not be
        // available to another task until it has also been given back
        // three times.
        os_mutex_give(p_handle);
        os_mutex_give(p_handle);
        os_mutex_give(p_handle);

        // Finish accessing the share resource, then release the semaphore.
        // Now the mutex can be taken by other tasks.
    }
    else
    {
        // Could not access the share resource.
    }
}

Param p_handle:

The handle of the mutex to be given.

Retval true:

Mutex was given successfully.

Retval false:

Mutex was failed to give.

Return:

The status of the mutex giving.