Document Details

UnbeatableClearQuartz2534

Uploaded by UnbeatableClearQuartz2534

ENSEA

Laurent Fiack

Tags

real-time operating systems rtos semaphores programming

Summary

This document is lecture notes on real-time operating systems (RTOS). It covers topics like semaphores, specifically focusing on binary semaphores. It describes scenarios of different processes and how interruptions affect concurrency. It also discusses implementations using C code. The document appears to be lecture notes for a course in real-time systems.

Full Transcript

Noyaux Temps-réel Les sémaphores Laurent Fiack Bureau D212/D060 – [email protected] Sémaphores binaires Sémaphores binaires Exemple : Traitements en interruptions #include "main.h" #include "usart.h" #include "tim.h" #include "gpio.h...

Noyaux Temps-réel Les sémaphores Laurent Fiack Bureau D212/D060 – [email protected] Sémaphores binaires Sémaphores binaires Exemple : Traitements en interruptions #include "main.h" #include "usart.h" #include "tim.h" #include "gpio.h" int main(void) { uint8_t input_char; HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); void USART1_IRQHandler(void) MX_USART1_UART_Init(); { process_char(input_char); HAL_UART_Receive_IT(&huart1, &input_char, 1); HAL_TIM_Base_Start_IT(&tim1); HAL_UART_Receive_IT(&huart1, &input_char, 1); HAL_UART_IRQHandler(&huart1); for(;;) } { } } void TIM1_IRQHandler(void) { process_something(); Et si les traitements sont longs ? HAL_TIM_IRQHandler(&htim1); } L. Fiack · RTOS 3 / 25 Sémaphores binaires Exemple : Traitements délégués dans une superboucle #include "main.h" int main(void) #include "usart.h" { #include "tim.h" HAL_Init(); #include "gpio.h" SystemClock_Config(); MX_GPIO_Init(); uint8_t input_char; MX_USART1_UART_Init(); uint8_t usart1_char_available = 0; HAL_UART_Receive_IT(&huart1, &input_char, 1); uint8_t tim1_overflowed = 0; HAL_TIM_Base_Start_IT(&tim1); for(;;) void USART1_IRQHandler(void) { { if (usart1_char_available) usart1_char_available = 1; { process_char(input_char); HAL_UART_Receive_IT(&huart1, &input_char, 1); } HAL_UART_IRQHandler(&huart1); if (tim1_overflowed) } { process_something(); } void TIM1_IRQHandler(void) } { } tim1_overflowed = 1; HAL_TIM_IRQHandler(&htim1); } Et les priorités ? L. Fiack · RTOS 4 / 25 Sémaphores binaires Exemple : Traitements délégués dans des tâches (1/2) #include "main.h" #include "usart.h" New ! #include "tim.h" void task_usart1(void * unused) #include "gpio.h" { HAL_UART_Receive_IT(&huart1, &input_char, 1); #include "FreeRTOS.h" for(;;) uint8_t input_char; { if (usart1_char_available) uint8_t usart1_char_available = 0; { uint8_t tim1_overflowed = 0; process_char(input_char); } } void USART1_IRQHandler(void) } { usart1_char_available = 1; void task_tim1(void * unused) { HAL_UART_Receive_IT(&huart1, &input_char, 1); HAL_TIM_Base_Start_IT(&tim1); HAL_UART_IRQHandler(&huart1); } for(;;) { if (tim1_overflowed) void TIM1_IRQHandler(void) { { process_something(); tim1_overflowed = 1; } } HAL_TIM_IRQHandler(&htim1); } } L. Fiack · RTOS 5 / 25 Sémaphores binaires Exemple : Traitements délégués dans des tâches (2/2) int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); xTaskCreate(task_usart1, "USART1", 256, NULL, 1, NULL); xTaskCreate(task_tim1, "TIM1", 256, NULL, 2, NULL); vTaskStartScheduler(); } Quel est le problème ? L. Fiack · RTOS 6 / 25 Sémaphores binaires Exemple : La bonne méthode, avec des sémaphores (1/2) #include "main.h" #include "usart.h" #include "tim.h" #include "gpio.h" void task_usart1(void * unused) #include "FreeRTOS.h" { HAL_UART_Receive_IT(&huart1, &input_char, 1); uint8_t input_char; for(;;) SemaphoreHandle_t sem_usart1; { SemaphoreHandle_t sem_tim1; xSemaphoreTake(sem_usart1, portMAX_DELAY); process_char(input_char); } void USART1_IRQHandler(void) } { xSemaphoreGive(sem_usart1); // Attention! Illégal void task_tim1(void * unused) { HAL_UART_Receive_IT(&huart1, &input_char, 1); HAL_TIM_Base_Start_IT(&tim1); HAL_UART_IRQHandler(&huart1); } for(;;) { xSemaphoreTake(sem_tim1, portMAX_DELAY); void TIM1_IRQHandler(void) process_something(); { } xSemaphoreGive(sem_tim1); // Attention! Illégal } HAL_TIM_IRQHandler(&htim1); } L. Fiack · RTOS 7 / 25 Sémaphores binaires Exemple : La bonne méthode, avec des sémaphores (2/2) En bref Les tâches sont dans l’état BLOCKED int main(void) { Elles deviennent READY grâce aux HAL_Init(); SystemClock_Config(); interruptions MX_GPIO_Init(); MX_USART1_UART_Init(); Si le timer est déclenché pendant le sem_usart1 = xSemaphoreCreateBinary(); traitement de l’USART1 : sem_tim1 = xSemaphoreCreateBinary(); La tâche préempte l’UART xTaskCreate(task_usart1, "USART1", 256, NULL, 1, NULL); xTaskCreate(task_tim1, "TIM1", 256, NULL, 2, NULL); Si un charactère arrive pendant le traitement vTaskStartScheduler(); du TIM1 : } L’interruption est traitée Mais le timer continue Le charactère est traité après L. Fiack · RTOS 8 / 25 Sémaphores binaires Syntaxe : Création d’un sémaphore Création d’un sémaphore SemaphoreHandle_t xSemaphoreCreateBinary(void); Paramètre de retour : SemaphoreHandle_t Handle pour manipuler le sémaphore NULL en cas d’erreur Destruction d’un sémaphore void xSemaphoreDelete(SemaphoreHandle_t xSemaphore); xSemaphore : Handle du sémaphore à détruire L. Fiack · RTOS 9 / 25 Sémaphores binaires Syntaxe : Manipulation d’un sémaphore Obtention d’un sémaphore BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait); xSemaphore : Handle du sémaphore à prendre xTicksToWait : Timeout avant de débloquer la tâche Attention ! Le sémaphore n’est pas pris Penser à faire de la gestion d’erreur Paramètre de retour : pdTRUE si le sémaphore est obtenu pdFALSE si le sémaphore n’est pas disponible après le timeout Libération d’un sémaphore BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore); xSemaphore : Handle du sémaphore à donner Paramètre de retour : pdTRUE si le sémaphore est libéré pdFALSE en cas d’échec L. Fiack · RTOS 10 / 25 Sémaphores binaires Dans une interruption Premier constat : Une interruption peut survenir à n’importe quel moment Lors de l’exécution de n’importe quelle tâche Elle n’est pas liée à une tâche Conséquences : Interruption dans un contexte particulier Utilisation de la pile système Et donc pas la pile de la tâche en cours d’exécution Deuxième constat : Take et Give appellent le scheduler Le scheduler peut effectuer un changement de tâche Et modifie donc le contexte Conséquences : Sauvegarde du contexte de l’interruption Pas de la tâche active Graves déconvenues ! L. Fiack · RTOS 11 / 25 Sémaphores binaires Solution Le problème void USART1_IRQHandler(void) { xSemaphoreGive(sem_usart1); // Attention! Illégal HAL_UART_Receive_IT(&huart1, &input_char, 1); HAL_UART_IRQHandler(&huart1); } La solution void USART1_IRQHandler(void) { BaseType_t higher_priority_task_woken = pdFALSE; xSemaphoreGiveFromISR(sem_usart1, &higher_priority_task_woken); HAL_UART_Receive_IT(&huart1, &input_char, 1); HAL_UART_IRQHandler(&huart1); portYIELD_FROM_ISR(higher_priority_task_woken); } L. Fiack · RTOS 12 / 25 Sémaphores binaires Syntaxe : Manipulation d’un sémaphore en interruption Libération d’un sémaphore BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken); xSemaphore : Handle du sémaphore à donner pxHigherPriorityTaskWoken est une sortie, et vaut pdTRUE si une tâche plus prioritaire est réveillée, pdFALSE sinon. Paramètre de retour : pdTRUE si le sémaphore est libéré pdFALSE en cas d’échec Appel manuel du scheduler portYIELD_FROM_ISR(BaseType_t pxHigherPriorityTaskWoken); Appelle le scheduler si pxHigherPriorityTaskWoken vaut pdTRUE L. Fiack · RTOS 13 / 25 Sémaphores mutex Sémaphores mutex Cas d’utilisation : Mémoire partagée SharedData est une simple variable globale Ou un tableau, ou une structure L’accès multiple doit être protégé pour éviter les incohérences L. Fiack · RTOS 15 / 25 Sémaphores mutex Ressource et section critique Ressource critique Variable (tableau, structure) ou périphérique commun à plusieurs tâches Une seule tâche peut y accéder à un instant donné On parle d’exclusion mutuelle. Section critique Aussi appelé Région ou Zone critique Partie du code qui accède à la ressource critique L. Fiack · RTOS 16 / 25 Sémaphores mutex Protection par blocage des interruptions fonction() {... taskENTER_CRITICAL();......... taskEXIT_CRITICAL();... } Interdit toutes les interruptions pendant tout le traitement de la région critique Peu recommandable pour une application temps-réel L. Fiack · RTOS 17 / 25 Sémaphores mutex Protection en bloquant la préemption fonction() {... vTaskSuspendAll();......... xTaskResumeAll();... } N’empêche pas les interruptions Mais empêche le changement de tâches Une tâche plus prioritaire ne peut pas s’exécuter À éviter également L. Fiack · RTOS 18 / 25 Sémaphores mutex Protection en utilisant un sémaphore Mutex fonction() {... xSemaphoreTake(sem_handle, SEM_DELAY);......... xSemaphoreGive(sem_handle);... } N’empêche pas les interruptions N’empêche pas la préemption Une tâche plus prioritaire peut s’exécuter Elle bloque si elle essaie de prendre le sémaphore C’est la bonne solution ! L. Fiack · RTOS 19 / 25 Sémaphores mutex Sémaphore d’exclusion mutuelle (ou sémaphore Mutex) C’est un sémaphore binaire spécialisé pour l’exclusion mutuelle Il possède trois caractéristiques supplémentaires : Inversion de priorité Protection contre la destruction La tâche ayant pris le sémaphore est protégée contre la destruction Accès récursif (Seulement les RecursiveMutex) De plus : Il ne doit être utilisé que pour l’exclusion mutuelle Il est plein par défaut Il ne peut être libéré que par la tâche qui l’a pris Il ne peut pas être pris par un serveur d’interruption L. Fiack · RTOS 20 / 25 Sémaphores mutex L’inversion de priorité : Le problème Il faudrait que t1 ne soit pas bloquée plus longtemps que le temps nécessaire à t3 pour libérer le sémaphore L. Fiack · RTOS 21 / 25 Sémaphores mutex L’inversion de priorité en action t1 n’est plus bloquée par t2 L. Fiack · RTOS 22 / 25 Sémaphores mutex Problème d’interbloquage (Deadlock) Solution : accéder aux sémaphores dans le même ordre L. Fiack · RTOS 23 / 25 Sémaphores mutex Gestion de la file d’attente des tâches Si plusieurs tâches sont en attente sur un mutex : La tâche la plus prioritaire est débloquée en premier L. Fiack · RTOS 24 / 25  Implémentation d'un sémaphore Par un simple indicateur : OUI NON S=1? 0 S Attente Section critique S = 1 : sémaphore libre (plein) S = 0 : sémaphore pris (vide) 1 S Mais mauvaise solution ! 197 Soient deux tâches accédant à la ressource critique : OUI NON OUI NON S=1? S=1? 0 S Attente 0 S Attente Section Section critique critique 1 S 1 S Tâche A Tâche B Si la tâche A est préemptée par la tâche B après le test du flag S, 198 INTERRUPTION puis PREEMPTION OUI NON OUI NON S=1? S=1? 0 S Attente 0 S Attente Section Section critique critique 1 S 1 S Tâche A Tâche B le sémaphore serait pris en même temps par les deux tâches ! 199 Bonne solution : 0 AX XCHG AX,S OUI NON AX = 1 ? Section Attente critique 1 S XCHG est une instruction "atomique" SWP sur ARM 200 Instruction atomique Bonne solution : pour tester puis écrire S 0 AX XCHG AX,S (S) TestAndSet OUI NON AX = 1 ? Section Attente critique 1 S XCHG est une instruction "atomique" SWP sur ARM 201 Fonctionnement avec deux tâches : 0 AX 0 AX XCHG AX,S XCHG AX,S OUI NON OUI NON Préemption AX = 1 ? AX = 1 ? Section Attente Section Attente critique critique 1 S 1 S Tâche A Tâche B 202 Sémaphores mutex Sémaphore à comptes Stocke un nombre entier positif ou nul SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount); uxMaxCount : Valeur maximale du sémaphore uxInitialCount : Valeur du sémaphore à la création Deux cas d’utilisation Compteur de requêtes Gestion de ressources L. Fiack · RTOS 25 / 25

Use Quizgecko on...
Browser
Browser