mutex not providing mutal exclusion

Hi, I’ve recently noticed some issues in my projects where mutex’s no longer seemed to provide mutual exclusion? I created a small test application with two tasks that exemplifies the issue i’m seeing. This is running with freeRTOS 9.0.0 ~~~

include <FreeRTOS.h>

include <platform.h>

include <VirtualSerialPort.h>

include <SEGGER_SYSVIEW.h>

VirtualSerialPort serial(0); static void HighPriorityTask( void* Params); static void LowPriorityTask( void* Params); xSemaphoreHandle mutexPtr = NULL; int main(void) { SystemClock_Config(); serial.Init();
mutexPtr = xSemaphoreCreateMutex();

if(mutexPtr == NULL)
{
    while(1);
}

SEGGER_SYSVIEW_Conf();

if (xTaskCreate( HighPriorityTask, ( const char * ) "HPT", 256, NULL, tskIDLE_PRIORITY + 2, NULL ) == pdTRUE)   
{
    if(xTaskCreate( LowPriorityTask, ( const char * ) "LPT", 256, NULL, tskIDLE_PRIORITY + 1, NULL ) == pdTRUE) 
        vTaskStartScheduler();
}
while (1);//shouldn’t get here } static void HighPriorityTask( void* Params) { volatile uint32_t temp = 0;
while(1)
{
    printf("HPTt mutex addr 0x%pn", mutexPtr);
    for(int numItr = 0; numItr < 10; numItr++)
    {
        uint32_t sleepTime = rand() %500;
        printf("HPTt sleeping for %i msn", sleepTime);
        vTaskDelay(sleepTime);
        printf("HPTt take mutex, wait indefinitelyn");
        if(xSemaphoreTake(mutexPtr,portMAX_DELAY) == pdTRUE)
        {
            printf("HPTt mutex takenn");

            uint32_t sleepTime = rand() %500;
            printf("HPTt sleeping for %i msn", sleepTime);
            vTaskDelay(sleepTime);
            for(int i = 0; i < 20000; i++)
            {
                temp += i;
            }
            if(xSemaphoreGive(mutexPtr) == pdTRUE)
            {
                printf("HPTt mutex givenn");
            }
            else
            {
                printf("HPTt mutex give failedn");
            }
        }
        else
        {
            printf("HPTt mutex take failed!n");
        }
    }
    printf("HPT DONE, sleep for 2 secn");
    vTaskDelay(100);
}
} static void LowPriorityTask( void* Params) { volatile uint32t temp = 0; uint32t num;
while(1)
{
    printf("tttttLPTtmutex addr 0x%pn", mutexPtr);
    vTaskDelay(rand() %500);
    for(int numItr = 0; numItr < 10; numItr++)
    {
        printf("tttttLPTt take mutex, wait indefinitelyn");
        if(xSemaphoreTake(mutexPtr,portMAX_DELAY) == pdTRUE)
        {
            printf("tttttLPTt mutex takenn");

            uint32_t sleepTime = rand() %500;
            printf("tttttLPTt sleeping for %i msn", sleepTime);
            vTaskDelay(sleepTime);

            if(xSemaphoreGive(mutexPtr) == pdTRUE)
            {
                printf("tttttLPTt mutex givenn");
            }
            else
            {
                printf("tttttLPTt mutex give failedn");
            }
        }
        else
        {
            printf("tttttLPTt mutex take failed!n");
        }
    }
    printf("tttttLPT DONE, sleep for 2 secn");
    vTaskDelay(2000);
}
} ~~~ Here’s an example of some output, with the problematic section in bold.
HPT mutex addr 0x20021e50 HPT sleeping for 432 ms HPT take mutex, wait indefinitely HPT mutex taken HPT sleeping for 5 ms HPT mutex given HPT sleeping for 490 ms HPT take mutex, wait indefinitely HPT mutex taken HPT sleeping for 29 ms HPT mutex given HPT sleeping for 104 ms HPT take mutex, wait indefinitely HPT mutex taken HPT sleeping for 492 ms HPT mutex given HPT sleeping for 497 ms LPT mutex addr 0x20021e50 HPT take mutex, wait indefinitely HPT mutex taken HPT sleeping for 172 ms LPT take mutex, wait indefinitely HPT mutex given HPT sleeping for 235 ms LPT mutex taken LPT sleeping for 268 ms HPT take mutex, wait indefinitely HPT mutex taken HPT sleeping for 341 ms LPT mutex given LPT take mutex, wait indefinitely HPT mutex given HPT DONE, sleep for 2 sec LPT mutex taken LPT sleeping for 476 ms HPT mutex addr 0x20021e50 HPT sleeping for 258 ms HPT take mutex, wait indefinitely HPT mutex taken HPT sleeping for 489 ms LPT mutex given LPT take mutex, wait indefinitely HPT mutex given HPT sleeping for 451 ms
Am I making an incorrected assumption or setting/using something incorrectly? I’m guessing there’s a stupid mistake in there somewhere that I’m not seeing. This is on a Cortex M7 port compiled with Keil (RVDS). Any suggestions are greately appriciated. thanks!

mutex not providing mutal exclusion

How is your printf() writing its output? Is it possible some print() statements are missing (and do you need mutual exclusion on the printf() too?)? Which port are you using? If your Cortex-M7 has an r0p1 core then you need to use the port layer in the FreeRTOS/source/portable/RVDS/ARMCM7/r0p1 directory to work around a silicon errata, otherwise you need to use the code in the FreeRTOS/source/portable/RVDS/ARMCM4F directory.

mutex not providing mutal exclusion

I’ve tried both the r0p1 port and ARM_CM4F port with identical results printf does single byte transfers through fputc, which gets forwarded to a ring buffer (which is thread-safe) and eventually out to a USB stack. It’s possible for two different strings characters to be interleaved with one another, but there won’t be any dropped data. I’ll hook up two different LED’s to eliminate printf as a possible culprit.

mutex not providing mutal exclusion

Here’s updated code with LED calls inside the area expected to be protected by the mutex. I would expect only one LED to be on at a time, but occassionally both LED’s are on at the same time. ~~~

include <FreeRTOS.h>

include <platform.h>

include <VirtualSerialPort.h>

include <SEGGER_SYSVIEW.h>

include <stm32f7xxGpio.h>

VirtualSerialPort serial(0); static void HighPriorityTask( void* Params); static void LowPriorityTask( void* Params); gpio led1(GPIOJ, gpio::PIN0, true); gpio led2(GPIOJ, gpio::PIN1, true); xSemaphoreHandle mutexPtr = NULL; int main(void) { InitMCU(false); SystemClock_Config(); serial.Init();
mutexPtr = xSemaphoreCreateMutex();

if(mutexPtr == NULL)
{
    while(1);
}

SEGGER_SYSVIEW_Conf();

if (xTaskCreate( HighPriorityTask, ( const char * ) "HPT", 256, NULL, tskIDLE_PRIORITY + 2, NULL ) == pdTRUE)   
{
    if(xTaskCreate( LowPriorityTask, ( const char * ) "LPT", 256, NULL, tskIDLE_PRIORITY + 1, NULL ) == pdTRUE) 
        vTaskStartScheduler();
}
while (1);//shouldn’t get here } void HighPriorityTask( void* Params) { volatile uint32_t temp = 0;
led1.Clear();

while(1)
{
    printf("HPTt mutex addr 0x%pn", mutexPtr);
    for(int numItr = 0; numItr < 10; numItr++)
    {
        uint32_t sleepTime = rand() %500;
        printf("HPTt sleeping for %i msn", sleepTime);
        vTaskDelay(sleepTime);
        printf("HPTt take mutex, wait indefinitelyn");
        if(xSemaphoreTake(mutexPtr,portMAX_DELAY) == pdTRUE)
        {
            led1.Set();
            printf("HPTt mutex takenn");

            uint32_t sleepTime = rand() %500;
            printf("HPTt working for %in", sleepTime);
            for(int w = 0; w < sleepTime*100000; w++)
            {
                temp += w;
            }
            led1.Clear();
// printf(“HPTt sleeping for %i msn”, sleepTime); // vTaskDelay(sleepTime); if(xSemaphoreGive(mutexPtr) == pdTRUE) { printf(“HPTt mutex givenn”); } else { printf(“HPTt mutex give failedn”); } } else { printf(“HPTt mutex take failed!n”); } } printf(“HPT DONE, sleep for 2 secn”); vTaskDelay(100); } } void LowPriorityTask( void* Params) { volatile uint32t temp = 0; uint32t num;
led2.Clear();

while(1)
{
    printf("tttttLPTtmutex addr 0x%pn", mutexPtr);
    vTaskDelay(rand() %500);
    for(int numItr = 0; numItr < 10; numItr++)
    {
        printf("tttttLPTt take mutex, wait indefinitelyn");
        if(xSemaphoreTake(mutexPtr,portMAX_DELAY) == pdTRUE)
        {
            led2.Set();
            printf("tttttLPTt mutex takenn");

            uint32_t sleepTime = rand() %500;
            printf("tttttLPTt working for %in", sleepTime);
            for(int w = 0; w < sleepTime*100000; w++)
            {
                temp += w;
            }
// printf(“tttttLPTt sleeping for %i msn”, sleepTime); // vTaskDelay(sleepTime);
            led2.Clear();
            if(xSemaphoreGive(mutexPtr) == pdTRUE)
            {
                printf("tttttLPTt mutex givenn");
            }
            else
            {
                printf("tttttLPTt mutex give failedn");
            }
        }
        else
        {
            printf("tttttLPTt mutex take failed!n");
        }
    }
    printf("tttttLPT DONE, sleep for 2 secn");
    vTaskDelay(2000);
}
} ~~~

mutex not providing mutal exclusion

It was all instrumentation issues – in the code above, the “mutex given” text was written after the mutex had been given (which suggests overlap when viewed on the screen). To add insult to injury, the polarity of the LED’s was active low, so they were being turned “off” when each was inside the critical section and on when outside the critical section. After moving the print outputs to be inside the mutex and correcting for active low LED outputs, everything is showing up as expected for the critical sections. Here are the code changes for the slim chance that anyone is interested: ~~~

include <FreeRTOS.h>

include <platform.h>

include <VirtualSerialPort.h>

include <SEGGER_SYSVIEW.h>

include <stm32f7xxGpio.h>

VirtualSerialPort serial(0); static void HighPriorityTask( void* Params); static void LowPriorityTask( void* Params); gpio led1(GPIOJ, gpio::PIN0, true); gpio led2(GPIOJ, gpio::PIN1, true); xSemaphoreHandle mutexPtr = NULL; StaticSemaphore_t xMutexBuffer; int main(void) { InitMCU(false); SystemClock_Config(); serial.Init();
mutexPtr = xSemaphoreCreateMutexStatic(&xMutexBuffer);

if(mutexPtr == NULL)
{
    while(1);
}

led1.Set();
led2.Set();
SEGGER_SYSVIEW_Conf();

uint8_t cBuff[2];
serial.CheckLastByte(cBuff, -1);

if (xTaskCreate( HighPriorityTask, ( const char * ) "HPT", 256, NULL, tskIDLE_PRIORITY + 2, NULL ) == pdTRUE)   
{
    if(xTaskCreate( LowPriorityTask, ( const char * ) "LPT", 256, NULL, tskIDLE_PRIORITY + 1, NULL ) == pdTRUE) 
        vTaskStartScheduler();
}
while (1);//shouldn’t get here } void HighPriorityTask( void* Params) { volatile uint32_t temp = 0;
while(1)
{
    printf("HPTt mutex addr 0x%pn", mutexPtr);
    for(int numItr = 0; numItr < 10; numItr++)
    {
        printf("HPT itr %in", numItr);
        uint32_t sleepTime = rand() %500 + 500;
        printf("HPTt sleeping for %i msn", sleepTime);
        vTaskDelay(sleepTime);
        uint8_t hptWait[] = "HPTt take mutex, wait indefinitelyn";
        serial.Output(hptWait, sizeof(hptWait), true);
        if(xSemaphoreTake(mutexPtr,portMAX_DELAY) == pdTRUE)
        {
            led1.Clear();

            printf("HPTt mutex takenn");

            uint32_t sleepTime = rand() %500 + 500;
            printf("HPTt working for %in", sleepTime);
            for(int w = 0; w < sleepTime*100000; w++)
            {
                temp += w;
            }
            led1.Set();
            uint8_t given[] = "HPTt mutex givenn";
            serial.Output(given, sizeof(given), true);
            if(xSemaphoreGive(mutexPtr) == pdTRUE)
            {
                    uint8_t giveDone[] = "HPTt give donen";
                    serial.Output(giveDone, sizeof(giveDone), true);
            }
            else
            {
                printf("HPTt mutex give failedn");
            }
        }
        else
        {
            printf("HPTt mutex take failed!n");
        }
    }
    printf("HPT DONE, sleep for 2 secn");
    vTaskDelay(100);
}
} void LowPriorityTask( void* Params) { volatile uint32t temp = 0; uint32t num;
while(1)
{
    printf("tttttLPTtmutex addr 0x%pn", mutexPtr);
    vTaskDelay(rand() %500 + 500);
    for(int numItr = 0; numItr < 10; numItr++)
    {
        printf("tttttLPT itr %in", numItr);
        uint8_t msg[] = "tttttLPTt take mutex, wait indefinitelyn";
        serial.Output(msg, sizeof(msg), true);
        if(xSemaphoreTake(mutexPtr,portMAX_DELAY) == pdTRUE)
        {
            led2.Clear();
            printf("tttttLPTt mutex takenn");

            uint32_t sleepTime = rand() %500 + 500;
            printf("tttttLPTt working for %in", sleepTime);
            for(int w = 0; w < sleepTime*100000; w++)
            {
                temp += w;
            }

            uint8_t giveMsg[] = "tttttLPTt give mutexn";
            serial.Output(giveMsg, sizeof(giveMsg), true);
            led2.Set();
            if(xSemaphoreGive(mutexPtr) == pdTRUE)
            {
                uint8_t giveDone[] = "tttttLPTt give donen";
                serial.Output(giveDone, sizeof(giveDone), true);
            }
            else
            {
                printf("tttttLPTt mutex give failedn");
            }
        }
        else
        {
            printf("tttttLPTt mutex take failed!n");
        }
    }
    printf("tttttLPT DONE, sleep for 2 secn");
    vTaskDelay(2000);
}
} ~~~ Some example output looks like this:
HPT mutex addr 0x20020ac0 HPT itr 0 HPT sleeping for 768 ms LPT mutex addr 0x20020ac0 LPT itr 0 LPT take mutex, wait indefinitely LPT mutex taken LPT working for 909 HPT take mutex, wait indefinitely LPT give mutex HPT mutex taken HPT working for 660 HPT mutex given LPT give done HPT give done HPT itr 1 HPT sleeping for 583 ms LPT itr 1 LPT take mutex, wait indefinitely LPT mutex taken LPT working for 741 HPT take mutex, wait indefinitely LPT give mutex HPT mutex taken HPT working for 760 HPT mutex given LPT give done HPT give done HPT itr 2 HPT sleeping for 967 ms LPT itr 2 LPT take mutex, wait indefinitely LPT mutex taken LPT working for 807 HPT take mutex, wait indefinitely LPT give mutex HPT mutex taken HPT working for 764 HPT mutex given LPT give done HPT give done HPT itr 3 HPT sleeping for 648 ms LPT itr 3 LPT take mutex, wait indefinitely LPT mutex taken LPT working for 747 HPT take mutex, wait indefinitely LPT give mutex HPT mutex taken HPT working for 574 HPT mutex given LPT give done HPT give done HPT itr 4 HPT sleeping for 973 ms LPT itr 4 LPT take mutex, wait indefinitely LPT mutex taken LPT working for 957
At first glance, it looks like “LPT give done” should not show up HPT is running, but this is because calls to serial.Output(x,x,true) are blocking calls that block/sleep the calling thread until that output is fully flushed. Thanks for the help Real Time Engineers ltd – getting another set of eyes was helpful.

mutex not providing mutal exclusion

Great – thanks for taking the time to report back.