Priority inheritance not working well

Good morning,

I have developed the following code to test how freeRTOS implements priority inheritance through mutex.
But when I run I notice that task 2 is executed before task 3 which should be executed by priority inheritance.

Task3-1 accedo s12
before take S12
after take S12
Task1-1 duermo
Task1-2 accedo s11
before take S11 -> Here the next task should be 3
Task2-1 duermo
Task2-2 acced0 s21
before take S21
after take S21
Before give S21
after give S21
Task2-3 espero periodo
Before give S12

Code:

#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif

#if CONFIG_FREERTOS_TIMER_TASK_PRIORITY
#define CONFIG_FREERTOS_TIMER_TASK_PRIORITY 24
#endif

#define configUSE_MUTEXES 1

#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) // la maxima prioridad



void CS (int ms);
/*
  definicion de task
*/
TaskHandle_t task1;
TaskHandle_t task2;
TaskHandle_t task3;

void vTask1(void *pvParameters);
void vTask2(void *pvParameters);
void vTask3( void *pvParameters );
/*
 Definicion de semaforos
*/
SemaphoreHandle_t semaforoS1;
SemaphoreHandle_t semaforoS2;

/*
  definicion de servidores
*/


// the setup function runs once when you press reset or power the board
void setup() {
  // initialize serial communication at 115200 bits per second:
   Serial.begin(115200);
  Serial.println(configUSE_MUTEXES);
  TickType_t xLastWakeTime;
  xLastWakeTime = xTaskGetTickCount(); //extraemos el tiempo

  /***********************************************************************Semaforos***********************************************************************/
  semaforoS1 = xSemaphoreCreateMutex();
  semaforoS2 = xSemaphoreCreateMutex();
  
  /***********************************************************************Tareas*************************************************************************************/
  // Create the task to access the shared resource.
  xTaskCreatePinnedToCore(
    vTask1
    ,  "Task1"
    ,  1024  // Stack size
    ,  (void*) xLastWakeTime
    ,  5  // Priority
    ,  &task1 
    ,  ARDUINO_RUNNING_CORE);
  xTaskCreatePinnedToCore(
    vTask2
    ,  "Task1"
    ,  1024  // Stack size
    ,  (void*) xLastWakeTime
    ,  3  // Priority
    ,  &task2 
    ,  ARDUINO_RUNNING_CORE);
  xTaskCreatePinnedToCore(
    vTask3
    ,  "Task1"
    ,  1024  // Stack size
    ,  (void*) xLastWakeTime
    ,  1  // Priority
    ,  &task3 
    ,  ARDUINO_RUNNING_CORE);
/********************************************************************* fin tareas *************************************************************************************/


}


void loop()
{
}




void vTask1( void *pvParameters )
{
  TickType_t xLastWakeTime;
 

  const TickType_t xDelay100ms = pdMS_TO_TICKS(100);
  const TickType_t xTicksToDelay = pdMS_TO_TICKS(10);

  vTaskDelay(pdMS_TO_TICKS(10)); //Realizamos una espera 10ms inicial 
  xLastWakeTime = (TickType_t) pvParameters; //extraemos el tiempo
  for (;;) {

    //para durante 1000
    Serial.println("Task1-1 duermo");
    CS(10);
    Serial.println("Task1-2 accedo s11");
    S11 () ; //accedemos al servidor 1
    Serial.println("Task1-3 espero periodo");
    vTaskDelayUntil( &xLastWakeTime, xDelay100ms ); //esperamos 100ms
   }

}

void vTask2( void *pvParameters )
{
  TickType_t xLastWakeTime;
 
 
  const TickType_t xDelay200ms = pdMS_TO_TICKS(200);
  const TickType_t xDelay60ms = pdMS_TO_TICKS(60);

  vTaskDelay(pdMS_TO_TICKS(10)); //Realizamos una espera 10ms inicial 
  xLastWakeTime = (TickType_t) pvParameters; //extraemos el tiempo
  for (;;) {
    Serial.println("Task2-1 duermo");
    CS(60);
    Serial.println("Task2-2 acced0 s21");
    S21 () ; //accedemos al servidor 1
    Serial.println("Task2-3 espero periodo");
    vTaskDelayUntil( &xLastWakeTime, xDelay200ms ); //esperamos 100ms
   }

}

void vTask3( void *pvParameters )
{

  TickType_t xLastWakeTime;
  const TickType_t xDelay400ms = pdMS_TO_TICKS(400);
  const TickType_t xDelay30ms = pdMS_TO_TICKS(30);

  vTaskDelay(pdMS_TO_TICKS(5)); //espera inicial de 5
  xLastWakeTime = (TickType_t) pvParameters; //extraemos el tiempo

  for (;;) {
    Serial.println("Task3-1 accedo s12");
    S12 () ;
    Serial.println("Task3-2 duermo");
    CS(30);
    Serial.println("Task3-3 accedo s22");
   S22 () ;
    Serial.println("Task3-4 espero periodo");
    vTaskDelayUntil( &xLastWakeTime, xDelay400ms ); //esperamos 100ms
   }

}
/*********************************** Servidores *********************************************************************************************************************/
// Servidor S1
void S11 (void) {
   Serial.println("before take S11");
  xSemaphoreTake( semaforoS1, portMAX_DELAY );
   Serial.println("after take S11");
  CS(10);
  Serial.println("Before give S11");
  xSemaphoreGive( semaforoS1 );
  Serial.println("after give S11"); 
}
void S12 (void) {
   Serial.println("before take S12");
  xSemaphoreTake( semaforoS1, portMAX_DELAY );
  Serial.println("after take S12");
  CS(20);
  Serial.println("Before give S12");
  xSemaphoreGive( semaforoS1 ); 
  Serial.println("after give S12");
}

// Servidor S2
void S21 (void) {
   Serial.println("before take S21");
  xSemaphoreTake( semaforoS2, portMAX_DELAY );
Serial.println("after take S21");
  CS(30);
  Serial.println("Before give S21");
  xSemaphoreGive( semaforoS2 ); 
  Serial.println("after give S21");
}

void S22 (void) {
  Serial.println("before take S22");
  xSemaphoreTake( semaforoS2, portMAX_DELAY );
   Serial.println("after take S22");
   CS(20); 
   Serial.println("Before give S22");
  xSemaphoreGive( semaforoS2 );
   Serial.println("after give S22");
}

void CS (int ms) {

  int i, j ;

    for (j = 0; j < ms; j++){
      for (i = 0; i < 1410; i++) ;
    }

}

Can you help me understand why this is happening and how to solve it? thanks in advance.

There is a lot to decipher in your post - grateful if you can provide a simpler explanation of the sequence in which the mutex is taken and given and where the deviation from the expected behaviour is. For example, use taskp1, taskp2, taskp3 to denote three tasks of priority 1, 2 and 3 respectively, then write something like this:

  1. taskp1 takes the mutex.
  2. taskp2 preempts p1, and attempts to take the mutex. taskp1 should now have the same priority as taskp2
  3. task1 runs again because taskp2 is blocked on the mutex.
  4. … etc.

Also a couple of other things just to make sure you are aware:

  • Serial.println() is not thread safe. Are you using the mtuex to protect writing to the serial port, or writing to the serial port from all the tasks with no mutual exclusion protection?
  • FreeRTOS does not implement a full priority inheritance scheme, because to do so would take more code than is in the kernel today and bloat both the RAM required and the execution time. As an example of the simplification - if taskp1 inherits the priority of taskp2, and then inherits the priority of taskp3, it will keep the taskp3 priority until it releases the mutex even if taskp3 is no longer blocked on the mutex.

Please also note that your void CS (int ms) function might be optimized out by the compiler when using an optimization level > 0.
You’d need to apply some additional (empiric) tricks like using volatile counter variables, but you should better use a real timer for a reliable and more precise ms - delay function.

1.taskp1 take the mutex
2.taskp5 up and try to get the same mutex
3.taskp1 inheritance the priority 5 and give the mutex
4.taskp5 execute the SC
6.taskp4 execute
7.taskp1 finished

I want see this result in log or trace but in log I see between 2 and 3 execute the taskp4.
I am solving the problem with serial because I don’t execute in SC. When I have the new log Inform with result or close the question.
thank you so much

What is SC ?
I think Serial.println can block internally allowing e.g. taskp4 being scheduled because taskp1/5 might be waiting for the completion of the serial output operation.

SC is a critical section.

I found a error in programming and right now. The program run well.

thank you so much for your help.