
Les sémaphores ont été mentionnés dans l'un des articles précédents (# 5). Leur tùche principale est de contrÎler l'accÚs aux ressources.
Articles précédents de la série:
Article # 18. Groupes d'indicateurs d'événements: services d'assistance et structures de donnéesArticle # 17. Groupes de drapeaux d'événements: introduction et services de baseArticle # 16. SignauxArticle # 15. Partitions de mémoire: services et structures de donnéesArticle # 14. Sections de mémoire: introduction et services de baseArticle # 13. Structures de données de tùche et appels d'API non pris en chargeArticle # 12. Services pour travailler avec des tùchesArticle # 11. Tùches: configuration et introduction à l'APIArticle # 10. Scheduler: fonctionnalités avancées et préservation du contexteArticle # 9. Scheduler: implémentationArticle # 8. Nucleus SE: conception interne et déploiementArticle # 7. Nucleus SE: IntroductionArticle # 6. Autres services RTOSArticle # 5. Interaction et synchronisation des tùchesArticle # 4. Tùches, changement de contexte et interruptionsArticle # 3. Tùches et planificationArticle # 2. RTOS: Structure et mode temps réel
Article # 1. RTOS: introduction.
Utiliser des sémaphores
Dans Nucleus SE, les sémaphores sont définis au stade de l'assemblage. Une application peut avoir jusqu'à 16 sémaphores. Si les sémaphores ne sont pas spécifiés, le code des appels de service et les structures de données ne sont pas inclus dans l'application.
Un sémaphore est un compteur de type
U8 dont l'accÚs est contrÎlé de maniÚre à ce que plusieurs tùches puissent l'utiliser. Une tùche peut diminuer la valeur du compteur de sémaphores (capture) ou l'augmenter (libération). Tenter de capturer un sémaphore avec une valeur de zéro peut entraßner une erreur ou une suspension de tùche, selon les paramÚtres d'appel d'API sélectionnés et la configuration de Nucleus SE.
Configuration de sémaphores
Nombre de sémaphores
Comme pour la plupart des objets Nucleus SE, le réglage des sémaphores est déterminé par les directives
#define dans
nuse_config.h . Le paramĂštre principal est
NUSE_SEMAPHORE_NUMBER , qui détermine le nombre de sémaphores dans l'application. Par défaut, le paramÚtre est défini sur 0 (les sémaphores ne sont pas utilisés dans l'application) et peut prendre n'importe quelle valeur jusqu'à 16. Une valeur incorrecte entraßnera une erreur de compilation, qui sera générée en
archivant nuse_config_check.h (ce fichier est inclus dans
nuse_config.c , ce qui signifie qu'il compile avec ce module), par conséquent, la directive
#error se
déclenchera .
Le choix d'une valeur différente de zéro sert d'activateur principal pour les sémaphores. Ce paramÚtre est utilisé lors de la définition des structures de données et leur taille dépend de sa valeur (pour plus de détails, voir plus loin dans cet article). De plus, une valeur différente de zéro active les paramÚtres de l'API.
Activer les appels API
Chaque fonction API (appel d'utilitaire) dans Nucleus SE est activée par la directive
#define dans
nuse_config.h . Pour les sémaphores, cela comprend:
NUSE_SEMAPHORE_OBTAIN
NUSE_SEMAPHORE_RELEASE
NUSE_SEMAPHORE_RESET
NUSE_SEMAPHORE_INFORMATION
NUSE_SEMAPHORE_COUNT
Par défaut, ils sont définis sur
FALSE , désactivant ainsi chaque appel de service et bloquant l'inclusion de code qui les implémente. Pour configurer des sémaphores, vous devez sélectionner les appels d'API nécessaires et définir les directives correspondantes sur
TRUE .
Ce qui suit est un extrait du fichier
nuse_config.h par défaut.
#define NUSE_SEMAPHORE_NUMBER 0 #define NUSE_SEMAPHORE_OBTAIN FALSE #define NUSE_SEMAPHORE_RELEASE FALSE #define NUSE_SEMAPHORE_RESET FALSE #define NUSE_SEMAPHORE_INFORMATION FALSE #define NUSE_SEMAPHORE_COUNT FALSE
Une fonction API activée s'il n'y a pas de sémaphores dans l'application entraßnera une erreur de compilation (à l'exception de
NUSE_Semaphore_Count () , qui est toujours activé). Si votre code utilise un appel d'API qui n'a pas été activé, une erreur de mise en page se produira car le code d'implémentation n'a pas été inclus dans l'application.
Appels de sémaphore utilitaire
Nucleus RTOS prend en charge huit appels de service qui offrent les fonctionnalités suivantes:
- Capture de sémaphore. Nucleus SE est implémenté dans la fonction NUSE_Semaphore_Obtain () .
- Relùchez le sémaphore. Dans Nucleus SE, il est implémenté dans la fonction NUSE_Semaphore_Release () .
- Retour du sémaphore à un état inutilisé avec la libération de toutes les tùches suspendues (redémarrage). Nucleus SE est implémenté dans NUSE_Semaphore_Reset () .
- Fournir des informations sur un sémaphore spécifique. Nucleus SE est implémenté dans NUSE_Semaphore_Information () .
- Renvoie le nombre de sémaphores configurés dans l'application. Nucleus SE implémenté dans NUSE_Semaphore_Count () .
- Ajout d'un nouveau sémaphore à l'application. Nucleus SE n'est pas implémenté.
- Suppression du sémaphore de l'application. Nucleus SE n'est pas implémenté.
- Retour des pointeurs vers tous les sémaphores. Nucleus SE n'est pas implémenté.
La mise en Ćuvre de chaque appel de service est dĂ©crite en dĂ©tail ci-dessous.
Appels utilitaires pour capturer et libérer des sémaphores
Les opĂ©rations fondamentales qui peuvent ĂȘtre effectuĂ©es sur les sĂ©maphores sont la capture et la libĂ©ration (diminution et augmentation de la valeur). Nucleus RTOS et Nucleus SE fournissent deux appels d'API de base pour ces opĂ©rations.
Capture de sémaphore
L'appel de l'utilitaire Nucleus RTOS pour capturer un sĂ©maphore est trĂšs flexible et vous permet de suspendre les tĂąches implicitement ou avec un dĂ©lai d'expiration spĂ©cifique si l'opĂ©ration ne peut pas ĂȘtre effectuĂ©e pour le moment, par exemple, si vous essayez de capturer un sĂ©maphore avec une valeur nulle. Nucleus SE offre les mĂȘmes fonctionnalitĂ©s, seule la pause de tĂąche est facultative et aucun dĂ©lai d'attente n'est implĂ©mentĂ©.
Défi pour capturer un sémaphore dans Nucleus RTOSPrototype d'appel de service:
STATUS NU_Obtain_Semaphore (sémaphore NU_SEMAPHORE *, suspension UNSIGNED);ParamÚtres:
sémaphore - pointeur vers le bloc de contrÎle de sémaphore fourni par l'utilisateur;
suspend - paramĂštre de suspension de tĂąche, peut prendre les valeurs
NU_NO_SUSPEND ou
NU_SUSPEND , ainsi que la valeur du délai d'expiration.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succÚs;
NU_UNAVAILABLE - le sémaphore avait une valeur nulle;
NU_INVALID_SEMAPHORE - pointeur invalide vers un sémaphore;
NU_INVALID_SUSPEND - tentative de pause à partir d'un thread non lié à une tùche;
NU_SEMAPHORE_WAS_RESET - le sémaphore a été réinitialisé alors que la tùche était suspendue.
Défi pour capturer un sémaphore dans Nucleus SECet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.
Prototype d'appel de service:
STATUS NUSE_Semaphore_Obtain (sémaphore NUSE_SEMAPHORE, suspension U8);ParamÚtres:
sémaphore - index (ID) du sémaphore utilisé;
suspend - paramĂštre de suspension de tĂąche, peut ĂȘtre
NUSE_NO_SUSPEND ou
NUSE_SUSPEND .
Valeur de retour:
NUSE_SUCCESS - l'appel s'est terminé avec succÚs;
NUSE_UNAVAILABLE - le sémaphore avait une valeur nulle;
NUSE_INVALID_SEMAPHORE - index de sémaphore invalide;
NUSE_INVALID_SUSPEND - une tentative de pause à partir d'un thread non lié à une tùche ou lorsque la fonctionnalité de blocage d'API est désactivée;
NUSE_SEMAPHORE_WAS_RESET - le sémaphore a été réinitialisé alors que la tùche a été suspendue;
Implémentation de la capture de sémaphore dans Nucleus SELa version du code de fonction
NUSE_Semaphore_Obtain () (aprÚs vérification des paramÚtres) est sélectionnée à l'aide de la compilation conditionnelle selon que la prise en charge des tùches de blocage (pause) est activée ou non. Considérez les deux options.
Si le verrou n'est pas activé, la logique de cet appel d'API est assez simple:
if (NUSE_Semaphore_Counter[semaphore] != 0) /* semaphore available */ { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; } else /* semaphore unavailable */ { return_value = NUSE_UNAVAILABLE; }
La valeur du compteur de sémaphores est vérifiée et, si elle n'est pas égale à zéro, diminue.
Si le verrouillage des tùches est activé, la logique devient plus complexe:
do { if (NUSE_Semaphore_Counter[semaphore] != 0) /* semaphore available */ { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else /* semaphore unavailable */ { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_UNAVAILABLE; } else { /* block task */ NUSE_Semaphore_Blocking_Count[semaphore]++; NUSE_Suspend_Task(NUSE_Task_Active, semaphore << 4) | NUSE_SEMAPHORE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND);
Certaines clarifications peuvent ĂȘtre utiles.
Le code est placé dans une
boucle do ... while , qui s'exécute alors que le paramÚtre
suspend est
NUSE_SUSPEND .
Si le sémaphore a une valeur non nulle, il diminue. La variable
suspend est définie sur
NUSE_NO_SUSPEND et l'appel API se termine et renvoie
NUSE_SUCESS .
Si le sémaphore est nul et que la variable de
suspension est définie sur
NUSE_NO_SUSPEND , l'appel d'API renvoie
NUSE_UNAVAILABLE . Si la suspension a été définie sur
NUSE_SUSPEND , la tùche s'interrompt. Une fois l'appel terminé (par exemple, lorsque la tùche reprend), si la valeur de retour est
NUSE_SUCCESS (qui indique que la tùche a été reprise aprÚs la libération du sémaphore et non aprÚs la réinitialisation), le cycle recommence depuis le début.
Sortie du sémaphore
L'appel d'utilitaire Ă l'API Nucleus RTOS pour libĂ©rer le sĂ©maphore est assez simple: la valeur du compteur de sĂ©maphore augmente et un message de rĂ©ussite est renvoyĂ©. Nucleus SE offre les mĂȘmes fonctionnalitĂ©s, mais avec une vĂ©rification de dĂ©bordement supplĂ©mentaire.
Défi de publier des sémaphores dans Nucleus RTOSPrototype d'appel de service:
STATUS NU_Release_Semaphore (NU_SEMAPHORE * sémaphore);ParamÚtres:
sémaphore - un pointeur vers un bloc de contrÎle de sémaphore fourni par l'utilisateur.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succÚs;
NU_INVALID_SEMAPHORE - Pointeur de sémaphore
non valide .
Défi de publier un sémaphore dans Nucleus SECet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.
Prototype d'appel de service:
STATUS NUSE_Semaphore_Release (sémaphore NUSE_SEMAPHORE);ParamÚtres:
sémaphore - L'index (ID) du sémaphore libéré.
Valeur de retour:
NUSE_SUCCESS - l'appel s'est terminé avec succÚs;
NUSE_INVALID_SEMAPHORE - index de sémaphore invalide;
NUSE_UNAVAILABLE - le sĂ©maphore a une valeur de 255 et ne peut pas ĂȘtre augmentĂ©.
Implémentation d'une version de sémaphore dans Nucleus SELe code de fonction
NUSE_Semaphore_Release () (aprÚs vérification des paramÚtres) est commun, que le verrouillage des tùches soit activé ou non. La valeur du compteur de sémaphores est vérifiée et si elle est inférieure à 255, elle augmente.
Un code supplémentaire est sélectionné à l'aide de la compilation conditionnelle si la prise en charge des appels de blocage d'API (suspension de tùche) est activée:
NUSE_CS_Enter(); if (NUSE_Semaphore_Counter[semaphore] < 255) { NUSE_Semaphore_Counter[semaphore]++; return_value = NUSE_SUCCESS; #if NUSE_BLOCKING_ENABLE if (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { U8 index; NUSE_Semaphore_Blocking_Count[semaphore]--; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_SEMAPHORE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == semaphore)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } #endif } else { return_value = NUSE_UNAVAILABLE; } NUSE_CS_Exit(); return return_value;
Si des tùches sont suspendues sur ce sémaphore, la premiÚre d'entre elles reprend.
L'article suivant décrit les appels d'API supplémentaires associés aux sémaphores et à leurs structures de données.
à propos de l'auteur: Colin Walls travaille dans l'industrie électronique depuis plus de trente ans, consacrant la majeure partie de son temps au micrologiciel. Il est maintenant ingénieur firmware chez Mentor Embedded (une division de Mentor Graphics). Colin Walls intervient souvent lors de conférences et séminaires, auteur de nombreux articles techniques et de deux livres sur le firmware. Vit au Royaume-Uni.
Blog professionnel
de Colin , e-mail: colin_walls@mentor.com.