New to RTOS, understanding semaphore delays

marifca wrote on Wednesday, June 11, 2014:

Hi,

I am new to RTOS world. Starting with FreeRTOS. I am using Freescale Coldfire V2 microcontrollers and managed to start several tasks running on it. But I am a bit confused regarding the delay used in semaphores. I have an interrupt giving a semaphore using xSemaphoreGiveFromISR() and a task blocking this accepts it using xSemaphoreTake() as in the following example

// A task that uses the semaphore.
void vAnotherTask( void * pvParameters )
{
// … Do other things.

if( xSemaphore != NULL )
{
    // See if we can obtain the semaphore.  If the semaphore is not available
    // wait 10 ticks to see if it becomes free.	
    if( xSemaphoreTake( xSemaphore, ( TickType_t ) 10 ) == pdTRUE )
    {
        // We were able to obtain the semaphore and can now access the
        // shared resource.

        // ..."My Code"

        // We have finished accessing the shared resource.  Release the 
        // semaphore.
        xSemaphoreGive( xSemaphore );
    }
    else
    {
        // We could not obtain the semaphore and can therefore not access
        // the shared resource safely.
    }
}

}

My question is what does this ( TickType_t ) 10 actually means or doing here? What happens to the “My code” block in the following three cases:

  1. xTicksToWait value is 0 … is “My code” executed with every tick? Then what is the the significance of giving the semaphore from an interrupt and an event tracking mechanism?
  2. xTicksToWait value is 10 …
  3. xTicksToWait value is MaxDelay (I guess 0xffffffff) and what is the difference in action between the used value of 0 and MaxDelay?

Also I would like to know what if I use

xSemaphoreTake( xSemaphore, ( TickType_t ) 10 );
//“My Code”
xSemaphoreGive( xSemaphore );

instead of the if-else structure shown above. Will it exit the task without executing “My code” if the semaphore cannot be taken? I am asking this because I have seen some code examples on a FreeRTOS book for PC showing such examples without the if( == pdTRUE) else{} statements.

Thanks in advance.

heinbali01 wrote on Wednesday, June 11, 2014:

Hi Mohammad,

The meaning of the xBlockTime parameter is well explained everywhere, on freertos.org, in the book, as well as in the header files:

sorry, text was doubled, see response below:

heinbali01 wrote on Wednesday, June 11, 2014:

Hi Mohammad,

The meaning of the xBlockTime parameter is well explained everywhere, on freertos.org, in the book, as well as in the header files:


 * @param xBlockTime The time in ticks to wait for the semaphore to become
 * available.  The macro portTICK_PERIOD_MS can be used to convert this to a
 * real time.  A block time of zero can be used to poll the semaphore.  A block
 * time of portMAX_DELAY can be used to block indefinitely (provided
 * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h).

So you can either poll a semaphore (using zero), wait a limited time, or wait for ever.

You say that your interrupt gives the semaphore using xSemaphoreGiveFromISR() and from within vAnotherTask() you also xSemaphoreGive() the semaphore?

The use of these two functions is correct, but why would you give from both locations?

Here are two useful scenarios for a semaphore:

  1. As a mutex: to protect a resource (as you say), which is shared among two or more tasks.
    If you really need to take the resource, you might want to wait much longer than 10 ticks.
    Once you’ve claimed the resource, be quick, don’t sleep and release it. (see also ‘configUSE_MUTEXES’)

  2. To wake up a task immediately after an interrupt has detected some situation. In that case the interrupt is “the giver”, and the task is “the taker”, in a one-to-one relation.

This method is very useful, because the interrupt can be kept short. It wakes up a task which can do the time-consuming things. The time between returning from the interrupt and the waking up of the task is very short, less than a µs (unless another higher-priority task is keeping the CPU busy).

If you want to wake up the task from more than once place, you might also consider using a queue and send messages to that task, so it knows who’s “the giver”.


void i2c_irq( )
{
    ....
    xSemaphoreGiveFromISR (i2c_Semaphore, &woken);
    ....
}

void vAnotherTask( void * pvParameters )
{
    for( ; ; )
    {
        if( xSemaphoreTake( i2c_Semaphore,
                      ( TickType_t ) 1000 ) == pdTRUE )
        {
            // The i2c interrupt woke up this task
            // don't xSemaphoreGive() it back
        }
    }
}

You had another question:

    for( ; ; )
    {
        xSemaphoreTake( xSemaphore, ( TickType_t ) 10 );
        //"My Code"
        xSemaphoreGive( xSemaphore );
    }

This is not very meaningful: the result of xSemaphoreTake() should be tested before you may assume that you have acquired the shared resource.
Suppose that another task has taken the resource for a time longer than 10 ticks, the above task might also start using it after a short time out.

A last example of the use of a semaphore, with taking only:

void ms_delay( TickType_t millisec )
{
    // Wait for a number of milliseconds
    TickType_t ticks;
    // Here delaySemaphore is never given, only taken
    // until a timeout occurs

    ticks = millisec / portTICK_PERIOD_MS;

    // Or in case your clock is faster than 1000 Hz
    ticks = ( configTICK_RATE_HZ * milisec + 500 ) /
        1000;

    xSemaphoreTake( delaySemaphore, ticks );
}

Did this answer all your questions?

Regards,
Hein

marifca wrote on Wednesday, June 11, 2014:

Thanks Hein for your replies.

void vAnotherTask( void * pvParameters ){} was copied from the FreeRTOS example on the web and not from my code. There is no xSemaphoreGive( xSemaphore ) in the task of my own code. Sorry for making it confusing.

So, now let me clarify my doubts regarding “So you can either poll a semaphore (using zero), wait a limited time, or wait for ever.” this line. I would like to know the underlying mechanism of this.

In the interrupt handling situation should I wait forever or should I poll the semaphore in the interrupt handler to make the interrupt latency as little as possible considering the interrupt handler has the highest priority? If I wait forever on the semaphore, does it not make the semaphore inactive? I have seen “wait forever” works in the interrupt handling situations in my code but did not understand how.

Or in other words, could you please give some example of when to use 0 (polling) delay on the semaphore and when to use “wait forever” and also what will be the consequence of waiting for a limited time in that example. An interrupt handler example would be appreciated.

Regards,
Arif

heinbali01 wrote on Wednesday, June 11, 2014:

Hi Arif,

The underlying mechanism of blocking versus polling a semaphore or queue?

Polling (timeout == 0): the call will only try to take the semaphore and return pdTRUE (non-zero) if it was successfully taken, otherwise pdFALSE (zero).

Blocking (timeout > 0): the call will also try to take the semaphore and if it succeeds, it will return immediately. If it can not be taken, then the timeout parameter determines the maximum number of clock ticks before waiting will be given up. While waiting, it will not consume any CPU time, whereas the polling method does take CPU time.

portMAX_DELAY (e.g. 0xffff) is a so-called sentinel value, it doesn’t mean 65535 clock-ticks, but it is treated as “for ever”.

In the interrupt handling situation should I wait forever or
should I poll the semaphore in the interrupt handler to make
the interrupt latency as little as possible considering the
interrupt handler has the highest priority?

The interrupt latency, i.e. the time between the interrupt (hardware) signal and the time that your IRQ handler becomes active, is not really influenced by your coding style. The latency depends on other competing interrupts, except when you use critical sections like here:

    extern volatile uint32_t ulCounterIRQ;
    {
        taskENTER_CRITICAL();
        // Execution of IRQ's is temporarily disabled
        // work safely with variables which can also be accessed
        // by your IRQ handler
        taskEXIT_CRITICAL();
    }

If you think well about your design, the use of critical sections can often be avoided. There are many locking mechanisms, other than disabling interrupts.

If I wait forever on the semaphore, does it not make the
semaphore inactive?

No, why? Your call will return as soon as the semaphore can be taken by your task, even if it has to wait for a year :slight_smile:

Personally, I would not use the “for ever” option. I would rather use a 1 sec timeout so that I can see that a task is still alive. It is hard to distinguish a permanently blocked task from a task that has got blocked because of stack corruption.

In a big embedded application, you might have many events from different sources. It would be expensive to create a new task with a new semaphore for every event. In stead you could make a task which receives commands, in stead of waiting for a semaphore:


QueueHandle_t xServerQueue;

void serverTask (void *pvParameters)
{

    // Create a queue capable of containing 10 uint32_t values.
    xServerQueue = xQueueCreate( 10, sizeof( uint32_t ) );
    for ( ; ; )
    {
        uint32_t ulCommand;
        if( xQueueReceive( xServerQueue, &ulCommand, 1000 ) )
        {
            switch( ulCommand )
            {
			case eCMD_AAA:
			case eCMD_BBB:
            }
        }
    }
}

Now every other task and every interrupt may send messages to the above task, using either QueueSend() or xQueueSendFromISR().

If you want to read more about FreeRTOS and the above subjects, you can find a really great manual/tutorial on http://shop.freertos.org

Regards,
Hein

marifca wrote on Wednesday, June 11, 2014:

Thanks a lot Hein. Appreciate your explanation.

Regards,
Arif