FreeRTOS Priority Inversion — Detection and Fix with Mutex Inheritance
Introduction
L’inversion de priorité est l’un des bugs les plus dangereux dans les systèmes RTOS. Il peut transformer un système temps-réel parfaitement conçu en un système imprévisible. Ce guide explique le mécanisme et comment le corriger avec FreeRTOS.
Le scénario classique
/* Tâche C — priorité 1 (basse) */
void task_C(void *pvParameters) {
xSemaphoreTake(shared_mutex, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(100)); // Long traitement
xSemaphoreGive(shared_mutex);
}
/* Tâche B — priorité 2 (moyenne) */
void task_B(void *pvParameters) {
while(1) {
compute_intensive_work(); // Préempte task_C !
}
}
/* Tâche A — priorité 3 (haute) */
void task_A(void *pvParameters) {
while(1) {
xSemaphoreTake(shared_mutex, portMAX_DELAY);
// BLOQUÉE car task_C détient le mutex
// Mais task_B s'exécute à la place de task_A !
xSemaphoreGive(shared_mutex);
}
}
Solution — Priority Inheritance Mutex
void app_init(void) {
/* xSemaphoreCreateMutex() implémente le PIP */
/* NE PAS utiliser xSemaphoreCreateBinary() */
shared_mutex = xSemaphoreCreateMutex();
configASSERT(shared_mutex != NULL);
xTaskCreate(task_A, "TaskA", 256, NULL, 3, NULL);
xTaskCreate(task_B, "TaskB", 256, NULL, 2, NULL);
xTaskCreate(task_C, "TaskC", 256, NULL, 1, NULL);
vTaskStartScheduler();
}
Monitoring avec Runtime Stats
/* Dans FreeRTOSConfig.h */
#define configGENERATE_RUN_TIME_STATS 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_TRACE_FACILITY 1
void print_task_stats(void) {
char stats_buffer[512];
vTaskGetRunTimeStats(stats_buffer);
printf("Task Stats:\r\n%s\r\n", stats_buffer);
}
Règles de conception
- Toujours utiliser
xSemaphoreCreateMutex()pour les ressources partagées - Ne jamais appeler
vTaskDelay()sous mutex - Utiliser Tracealyzer ou SystemView pour visualiser les inversions
- Concevoir les priorités avec des gaps suffisants entre tâches
Conclusion
L’inversion de priorité a causé des défaillances critiques dans des systèmes embarqués réels. FreeRTOS fournit les outils nécessaires — à condition de choisir le bon type de mutex et de concevoir correctement les priorités des tâches.