
Cet article poursuit l'examen des sémaphores.
Services de sémaphore auxiliaires
Nucleus RTOS dispose de quatre appels d'API qui fournissent des fonctionnalités liées aux sémaphores: réinitialisation d'un sémaphore, récupération des informations de sémaphore, récupération du nombre de sémaphores dans une application et récupération de pointeurs vers tous les sémaphores d'une application. Les trois premiers d'entre eux sont implémentés dans Nucleus SE.
Articles précédents de la série:
Article # 19. Sémaphores: introduction et services de baseArticle # 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.
Réinitialiser le sémaphore
Cet appel d'API réinitialise le sémaphore à son état initial non utilisé. Cette fonction d'API est inhabituelle par rapport aux fonctions d'autres objets du noyau, car malgré le fait qu'elle effectue une réinitialisation, elle définit non seulement le compteur à la valeur initiale, mais une nouvelle valeur de compteur initiale est transmise dans l'appel. Toute tâche qui a été interrompue sur le sémaphore reprend et renvoie le code
NUSE_SEMAPHORE_WAS_RESET dans Nucleus SE et dans Nucleus RTOS,
NU_SEMAPHORE_RESET .
Appel pour réinitialiser le sémaphore dans Nucleus RTOSPrototype d'appel de service:
STATUS NU_Reset_Semaphore (NU_SEMAPHORE * sémaphore, UNSIGNED initial_count);Paramètres:
sémaphore - pointeur vers le bloc de contrôle de sémaphore fourni par l'utilisateur;
initial_count - la valeur à laquelle le sémaphore sera défini.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_SEMAPHORE - Pointeur de sémaphore
non valide .
Appel pour réinitialiser 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_Reset (sémaphore NUSE_SEMAPHORE, U8 initial_count);Paramètres:
sémaphore - index (ID) du sémaphore vidé;
initial_count - la valeur à laquelle le sémaphore sera défini.
Valeur de retour:
NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_SEMAPHORE - index de sémaphore invalide.
Implémentation d'une réinitialisation de sémaphore dans Nucleus SELa tâche principale de la fonction API
NUSE_Semaphore_Reset () consiste à définir l'élément
NUSE_Semaphore_Counter [] correspondant à la valeur spécifiée (après vérification des paramètres).
Si le verrouillage des tâches est activé, le code suivant est requis pour déverrouiller les tâches:
while (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { U8 index; /* check whether any tasks are blocked */ /* on this 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_SEMAPHORE_WAS_RESET; NUSE_Task_Status[index] = NUSE_READY; break; } } NUSE_Semaphore_Blocking_Count[semaphore]--; } #if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER NUSE_Reschedule(NUSE_NO_TASK); #endif
Chaque tâche suspendue sur le sémaphore est marquée comme «terminée» et le code de suspension de tâche renvoie
NUSE_SEMAPHORE_WAS_RESET . Une fois ce processus terminé, si le planificateur de priorité est utilisé, l'appel initialise
NUSE_Reschedule () , car une ou plusieurs tâches avec une priorité plus élevée peuvent passer à l'état prêt et attendent de reprendre.
Informations sur le sémaphore
Cet appel d'utilitaire renvoie des informations sur le sémaphore. L'implémentation de cet appel dans Nucleus SE diffère de Nucleus RTOS en ce que moins d'informations sont renvoyées, car le nommage des objets et l'ordre de la suspension ne sont pas pris en charge, et la suspension des tâches elle-même peut être désactivée.
Appel d'informations sur les sémaphores dans Nucleus RTOSPrototype d'appel de service:
STATUS NU_Semaphore_Information (NU_SEMAPHORE * sémaphore, nom CHAR *, UNSIGNED * current_count, OPTION * suspend_type, UNSIGNED * tasks_waiting, NU_TASK ** first_task);Paramètres:
sémaphore - un pointeur vers le bloc de contrôle de sémaphore sur lequel les informations sont requises;
nom - pointeur sur le
nom à 8 caractères du sémaphore, avec zéro octet de fin inclus dans cette zone;
current_count - un pointeur sur une variable qui prendra la valeur actuelle du compteur de sémaphore;
suspend_type - un pointeur vers une variable qui acceptera le type de tâche suspendue, peut prendre les valeurs
NU_FIFO et
NU_PRIORITY ;
task_waiting - un pointeur sur une variable qui prendra le nombre de tâches suspendues dans le sémaphore;
first_task - un pointeur vers une variable de type
NU_TASK , qui prendra un pointeur vers l'unité de contrôle de la première tâche suspendue.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_SEMAPHORE - Pointeur de sémaphore
non valide .
Appel d'informations sur les sémaphores 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_Information (sémaphore NUSE_SEMAPHORE, U8 * current_count, U8 * tasks_waiting, NUSE_TASK * first_task);Paramètres:
sémaphore - un index d'un sémaphore sur lequel il est nécessaire de fournir des informations;
current_count - un pointeur sur une variable qui prendra la valeur actuelle du compteur de sémaphore;
tasks_waiting - un pointeur sur une variable qui prendra le nombre de tâches suspendues sur ce sémaphore (rien n'est retourné si la prise en charge de la suspension des tâches est désactivée);
first_task - un pointeur vers une variable de type
NUSE_TASK , qui prendra l'index de la première tâche suspendue (rien n'est retourné si la prise en charge des tâches de pause est désactivée)
Valeur de retour:
NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_SEMAPHORE - index de sémaphore invalide;
NUSE_INVALID_POINTER - un ou plusieurs paramètres de pointeur sont incorrects.
Implémentation d'informations sur les sémaphores dans Nucleus SEL'implémentation de cet appel d'API est assez simple:
NUSE_CS_Enter(); *current_count = NUSE_Semaphore_Counter[semaphore]; #if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Semaphore_Blocking_Count[semaphore]; if (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_SEMAPHORE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == semaphore)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif NUSE_CS_Exit(); return NUSE_SUCCESS;
La fonction renvoie l'état du sémaphore. Ensuite, si la fonctionnalité de blocage d'appels API est activée, le nombre de tâches en attente et l'index de la première sont renvoyés (sinon, ces paramètres sont définis sur 0).
Obtenir le nombre de sémaphores
Cet appel d'utilitaire renvoie le nombre de sémaphores dans l'application. Dans Nucleus RTOS, cette valeur change au fil du temps et la valeur de retour correspond au nombre actuel de sémaphores, et dans Nucleus SE, la valeur de retour est définie au stade de l'assemblage et ne change plus.
Appel d'un compteur de sémaphores dans Nucleus RTOSPrototype d'appel de service:
UNSIGNED NU_Established_Semaphores (VOID);Paramètres:
Sont absents.
Valeur de retour:
Le nombre de sémaphores créés dans l'application.
Appel d'un compteur de sémaphores dans Nucleus SECet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.
Prototype d'appel de service:
U8 NUSE_Semaphore_Count (void);Paramètres:
Sont absents.
Valeur de retour:
Le nombre de sémaphores configurés dans l'application.
Implémentation de compteurs de sémaphores dans Nucleus SEL'implémentation de cet appel API est assez simple: la valeur du symbole
#define NUSE_SEMAPHORE_NUMBER est
retournée .
Structures de données
Les sémaphores utilisent deux ou trois tableaux de structures de données (en RAM et ROM), qui, comme tous les autres objets Nucleus SE, sont un ensemble de tables dont la taille dépend du nombre de sémaphores dans l'application et des paramètres sélectionnés.
Je recommande fortement que le code d'application n'utilise pas un accès direct à ces structures de données, mais s'y réfère via les fonctions API fournies. Cela évitera l'incompatibilité avec les futures versions de Nucleus SE et les effets secondaires indésirables, ainsi que simplifiera le portage de l'application vers Nucleus RTOS. Pour une meilleure compréhension du fonctionnement du code d'appel de service et pour le débogage, un aperçu détaillé des structures de données est donné ci-dessous.
Données RAM
Ces données ont la structure suivante:
NUSE_Semaphore_Counter [] - un tableau de type
U8 qui a une entrée pour chaque sémaphore configuré, il stocke la valeur du compteur.
NUSE_Semaphore_Blocking_Count [] - un tableau de type
U8 , contient des compteurs de tâches bloquées sur chaque sémaphore. Ce tableau existe uniquement si la fonctionnalité de blocage d'appels API est activée.
NUSE_Semaphore_Counter [] est initialisé à la valeur initiale (voir "Données dans la ROM" ci-dessous) et
NUSE_Semaphore_Blocking_Count [] est réinitialisé à l' aide de
NUSE_Init_Semaphore () au démarrage de Nucleus SE. L'un des articles suivants fournira une description complète des procédures de démarrage de Nucleus SE.
Voici les définitions de ces structures de données dans le fichier
nuse_init.c .
RAM U8 NUSE_Semaphore_Counter[NUSE_SEMAPHORE_NUMBER]; #if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Semaphore_Blocking_Count[NUSE_SEMAPHORE_NUMBER]; #endif
Données ROM
Structure des données:
NUSE_Semaphore_Initial_Value [] - un tableau de type
U8 , ayant un enregistrement pour chaque sémaphore, ce sont les valeurs initiales des sémaphores.
Cette structure de données est déclarée et initialisée (statiquement) dans
nuse_config.c :
ROM U8 NUSE_Semaphore_Initial_Value[NUSE_SEMAPHORE_NUMBER] = { /* semaphore initial count values */ };
La quantité de mémoire pour les sémaphores
Comme tous les objets du noyau Nucleus SE, la quantité de données nécessaires pour les sémaphores est prévisible.
La quantité de mémoire en ROM (en octets) pour tous les sémaphores de l'application est
NUSE_SEMAPHORE_NUMBER .
La quantité de mémoire en RAM (en octets) pour tous les sémaphores dans l'application avec des appels activés à l'API de verrouillage peut être calculée comme suit:
NUSE_SEMAPHORE_NUMBER * 2
Sinon, c'est
NUSE_SEMAPHORE_NUMBER .
Appels d'API non réalisés
Trois appels d'API pour les sémaphores présents dans Nucleus RTOS ne sont pas implémentés dans Nucleus SE.
Création de sémaphores
Cet appel API crée un sémaphore. Il n'y a pas besoin de Nucleus SE car les sémaphores sont créés statiquement.
Prototype d'appel de service:
STATUS NU_Create_Semaphore (NU_SEMAPHORE * sémaphore, nom CHAR *, UNSIGNED initial_count, OPTION suspend_type);Paramètres:
sémaphore - un pointeur vers un bloc de contrôle de sémaphore fourni par l'utilisateur; il est utilisé pour contrôler les sémaphores dans d'autres appels d'API;
nom - un pointeur sur le nom du sémaphore à 8 caractères, avec l'octet nul de fin activé;
initial_count - la valeur initiale du sémaphore;
suspend_type - indique le principe de la pause d'une tâche sur un sémaphore. Il peut prendre les valeurs
NU_FIFO et
NU_PRIORITY , correspondant au principe de FIFO (First-in-First-Out) et l'ordre de priorité de la suspension des tâches.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_SEMAPHORE - Dit que le pointeur vers le bloc de contrôle du sémaphore est
NULL ou est déjà utilisé;
NU_INVALID_SUSPEND - paramètre
suspend_type non
valide .
Suppression du sémaphore
Cet appel d'API supprime le sémaphore créé précédemment. Nucleus SE n'est pas nécessaire car les sémaphores sont créés statiquement et ne peuvent pas être supprimés.
Prototype d'appel de service:
STATUS NU_Delete_Semaphore (NU_SEMAPHORE * semaphore);Paramètres:
sémaphore - pointeur vers le bloc de contrôle du sémaphore.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_SEMAPHORE - Pointeur de sémaphore
non valide .
Pointeurs vers les sémaphores
Cet appel API forme une liste séquentielle de pointeurs vers tous les sémaphores du système. Il n'a pas besoin de Nucleus SE, car les sémaphores sont identifiés par un simple index, pas un pointeur.
Prototype d'appel de service:
UNSIGNED NU_Semaphore_Pointers (NU_SEMAPHORE ** pointer_list, UNSIGNED maximum_pointers);Paramètres:
pointer_list - un pointeur vers un tableau de pointeurs
NU_SEMAPHORE , ce tableau est rempli de pointeurs vers des sémaphores;
maximum_pointers - le nombre maximum de pointeurs dans le tableau.
Valeur de retour:
Le nombre de pointeurs
NU_SEMAPHORE dans le tableau.
Compatible avec Nucleus RTOS
Comme pour tous les autres objets Nucleus SE, l'objectif était de maximiser la compatibilité du code d'application avec Nucleus RTOS. Les sémaphores ne font pas exception et, du point de vue de l'utilisateur, ils sont implémentés de la même manière que dans Nucleus RTOS. Il y a aussi une certaine incompatibilité, que j'ai jugée acceptable étant donné que le code final deviendra plus compréhensible et plus efficace en termes de quantité de mémoire requise. Sinon, les appels d'API Nucleus RTOS peuvent être utilisés presque directement comme appels Nucleus SE.
Identificateurs d'objet
Dans Nucleus RTOS, tous les objets sont décrits par des structures de données (unités de contrôle) d'un type spécifique. Un pointeur vers cette unité de contrôle sert d'identifiant pour le sémaphore. J'ai décidé que dans Nucleus SE, une approche différente est nécessaire pour une utilisation efficace de la mémoire: tous les objets du noyau sont décrits par un ensemble de tables en RAM et / ou ROM. La taille de ces tables est déterminée par le nombre d'objets configurés de chaque type. L'identifiant d'un objet particulier est l'index dans ce tableau. J'ai donc défini
NUSE_SEMAPHORE comme l'équivalent de
U8 , une variable (pas un pointeur) de ce type sert d'identifiant pour le sémaphore. Cette légère incompatibilité est facile à gérer si le code est porté de Nucleus SE vers Nucleus RTOS et vice versa. En règle générale, aucune opération n'est effectuée sur les identificateurs d'objet autres que le déplacement et le stockage.
Nucleus RTOS prend également en charge les noms de sémaphores. Ces noms sont utilisés uniquement pour le débogage. Je les ai exclus de Nucleus SE pour économiser de la mémoire.
Taille du comptoir
Sur Nucleus RTOS, le compteur de sémaphores est de type
unsigned , qui est généralement une variable 32 bits. Nucleus SE a un compteur 8 bits, mais cela peut être facilement changé. Normalement, Nucleus RTOS ne vérifie pas le débordement du sémaphore. L'appel à l'API Nucleus SE ne permettra pas d'attribuer au compteur des valeurs supérieures à 255.
Appels d'API non réalisés
Nucleus RTOS prend en charge huit appels d'utilitaire pour travailler avec des sémaphores. Parmi ceux-ci, trois ne sont pas implémentés dans Nucleus SE. Les détails de ces défis, ainsi que la décision de les exclure de Nucleus SE, ont été décrits ci-dessus.
L'article suivant examine les boîtes aux lettres.
À 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.