Toute la vérité sur RTOS. Article # 24. Files d'attente: services auxiliaires et structures de données



Dans cet article, nous continuerons à considérer les files d'attente.

Services de file d'attente secondaire


Nucleus RTOS dispose de quatre appels d'API qui fournissent des fonctions auxiliaires liées aux files d'attente: réinitialisation d'une file d'attente, obtention d'informations sur les files d'attente, obtention du nombre de files d'attente dans une application et obtention de pointeurs vers toutes les files d'attente d'une application. Les trois premières fonctions sont implémentées dans Nucleus SE.

Articles précédents de la série:

Article # 23. Files d'attente: introduction et services de base
Article # 22. Boîtes aux lettres: services auxiliaires et structures de données
Article # 21. Boîtes aux lettres: introduction et services de base
Article # 20. Sémaphores: services auxiliaires et structures de données
Article # 19. Sémaphores: introduction et services de base
Article # 18. Groupes d'indicateurs d'événements: services d'assistance et structures de données
Article # 17. Groupes de drapeaux d'événements: introduction et services de base
Article # 16. Signaux
Article # 15. Partitions de mémoire: services et structures de données
Article # 14. Sections de mémoire: introduction et services de base
Article # 13. Structures de données de tâche et appels d'API non pris en charge
Article # 12. Services pour travailler avec des tâches
Article # 11. Tâches: configuration et introduction à l'API
Article # 10. Scheduler: fonctionnalités avancées et préservation du contexte
Article # 9. Scheduler: implémentation
Article # 8. Nucleus SE: conception interne et déploiement
Article # 7. Nucleus SE: Introduction
Article # 6. Autres services RTOS
Article # 5. Interaction et synchronisation des tâches
Article # 4. Tâches, changement de contexte et interruptions
Article # 3. Tâches et planification
Article # 2. RTOS: Structure et mode temps réel
Article # 1. RTOS: introduction.

Réinitialisation de la file d'attente


Cet appel d'API réinitialise la file d'attente à son état d'origine non utilisé. Tous les messages stockés dans la file d'attente seront perdus. Toutes les tâches suspendues dans la file d'attente reprendront avec le code retour NUSE_QUEUE_WAS_RESET .

Appel de réinitialisation de file d'attente dans Nucleus RTOS
Prototype d'appel de service:
STATUS NU_Reset_Queue (file d'attente NU_QUEUE *);

Paramètres:
queue - un pointeur vers un bloc de contrôle de file d'attente fourni par l'utilisateur.

Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_QUEUE - pointeur de file d'attente non valide.

Appel de réinitialisation de file d'attente dans Nucleus SE
Cet appel d'utilitaire prend en charge la fonctionnalité principale de l'API RTOS Nucleus.

Prototype d'appel de service:
STATUS NUSE_Queue_Reset (file d'attente NUSE_QUEUE);

Paramètres:
queue - index (ID) de la file d'attente vidée.

Valeur de retour:
NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_QUEUE - index de file d'attente non valide.

Implémentation de la réinitialisation de file d'attente dans Nucleus SE
Le code de la fonction NUSE_Queue_Reset (après vérification des paramètres) est assez simple. Les index de la tête et de la queue de la file d'attente, ainsi que le compteur de messages dans la file d'attente, se voient attribuer une valeur nulle.

Si le verrouillage des tâches est activé, un code supplémentaire est responsable de la restauration des tâches suspendues:

while (NUSE_Queue_Blocking_Count[queue] != 0) { U8 index; /* check whether any tasks are blocked */ /* on this queue */ for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_QUEUE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == queue)) { NUSE_Task_Blocking_Return[index] = NUSE_QUEUE_WAS_RESET; NUSE_Task_Status[index] = NUSE_READY; break; } } NUSE_Queue_Blocking_Count[queue]--; } #if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER NUSE_Reschedule(NUSE_NO_TASK); #endif 

Chaque tâche en pause dans la file d'attente se voit attribuer un état «prêt» avec un code retour NUSE_QUEUE_WAS_RESET . Une fois ce processus terminé, si le planificateur de priorité est utilisé, la fonction NUSE_Reschedule () est appelée , car une ou plusieurs tâches avec une priorité élevée peuvent être prêtes à être exécutées.

Obtention d'informations sur la file d'attente


Cet appel de service fournit des informations sur la file d'attente. L'implémentation de cet appel dans Nucleus SE diffère de Nucleus RTOS en ce qu'il renvoie moins d'informations, car la dénomination des objets, la longueur variable des messages et l'ordre de pause des tâches ne sont pas pris en charge et le verrouillage des tâches peut être désactivé.

Appel à des informations de file d'attente dans Nucleus RTOS
Prototype d'appel de service:

STATUT NU_Queue_Information (NU_QUEUE * file d' attente, CHAR * nom, start_address ** NUL, UNSIGNED * queue_size, UNSIGNED * disponible, UNSIGNED * messages, OPTION * message_type, UNSIGNED * message_size, OPTION * suspend_type, UNSIGNED * tasks_waiting, NU_TASK ** first_task);

Paramètres:

file d'attente - un pointeur vers un bloc de contrôle de file d'attente fourni par l'utilisateur;
nom - pointeur vers la région à 8 caractères pour le nom du message dans la file d'attente;
start_address - un pointeur vers un pointeur dans lequel l'adresse du début de la zone de données de file d'attente sera écrite;
queue_size - un pointeur vers une variable pour stocker le nombre total d'éléments UNSIGNED dans la file d'attente;
available - un pointeur sur une variable pour stocker le nombre d'éléments UNSIGNED disponibles dans la file d'attente;
messages - un pointeur sur une variable pour stocker le nombre actuel de messages dans la file d'attente;
message_type - un pointeur vers une variable pour stocker le type de messages pris en charge par la file d'attente. Les valeurs valides sont NU_FIXED_SIZE et NU_VARIABLE ;
message_size - un pointeur vers une variable pour stocker le nombre d'éléments de données UNSIGNED dans chaque message de la file d'attente. Si la file d'attente prend en charge les messages de longueur variable, ce nombre indique la longueur maximale des messages;
suspend_type - un pointeur vers une variable pour stocker le type de suspension des tâches. Les valeurs valides sont NU_FIFO et NU_PRIORITY ;
tasks_waiting - un pointeur sur une variable pour stocker le nombre de tâches suspendues dans cette file d'attente;
first_task - pointeur vers le pointeur de tâche, dans lequel le pointeur de la première tâche suspendue est placé.

Valeur de retour:

NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_QUEUE - pointeur de file d'attente non valide.

Appel d'informations sur la file d'attente dans Nucleus SE
Cet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.

Prototype d'appel de service:

STATUS NUSE_Queue_Information (file d'attente NUSE_QUEUE, ADDR * start_address, U8 * queue_size, U8 * available, U8 * messages, U8 * tasks_waiting, NUSE_TASK * first_task);

Paramètres:

file d'attente - index de la file d'attente pour laquelle des informations sont demandées;
start_address - pointeur vers une variable de type ADDR , qui stockera l'adresse du début de la zone de données de la file d'attente;
queue_size - un pointeur vers une variable de type U8 , qui stockera le nombre total de messages pouvant tenir dans la file d'attente;
disponible - un pointeur sur une variable de type U8 , qui stockera le nombre de places libres dans la file d'attente;
messages - un pointeur sur une variable de type U8 , qui stockera le nombre actuel de messages dans la file d'attente;
tasks_waiting - un pointeur vers une variable dans laquelle le nombre de tâches suspendues dans cette file d'attente sera stocké (rien n'est retourné si le verrouillage des tâches est désactivé);
first_task - un pointeur vers une variable de type NUSE_TASK dans laquelle l'index de la première tâche suspendue sera stocké (rien n'est retourné si le verrouillage de tâche est désactivé).

Valeur de retour:

NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_QUEUE - index de file d'attente non valide;
NUSE_INVALID_POINTER - un ou plusieurs paramètres de pointeur sont incorrects.

Implémentation de l'affichage des informations de file d'attente dans Nucleus SE

L'implémentation de cet appel d'API est assez simple:

 *start_address = NUSE_Queue_Data[queue]; *queue_size = NUSE_Queue_Size[queue]; *available = NUSE_Queue_Size[queue] - NUSE_Queue_Items[queue]; *messages = NUSE_Queue_Items[queue]; #if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Queue_Blocking_Count[queue]; if (NUSE_Queue_Blocking_Count[queue] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_QUEUE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == queue)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif 

La fonction renvoie l'état de la file d'attente. Ensuite, si le verrouillage des tâches est activé, le nombre de tâches en attente et l'index de la première d'entre elles sont renvoyés (sinon, les deux paramètres sont définis sur 0).

Obtenir le nombre de files d'attente


Cet appel d'utilitaire renvoie le nombre de files d'attente configurées dans l'application. Dans Nucleus RTOS, leur nombre peut changer au fil du temps et la valeur de retour indiquera le nombre actuel de files d'attente. Dans Nucleus SE, la valeur de retour est définie pendant la phase de génération et ne peut pas être modifiée.

Appel du compteur de files d'attente dans Nucleus RTOS
Prototype d'appel de service:
UNSIGNED NU_Established_Queues (VOID);

Paramètres:
Sont absents.

Valeur de retour:
Le nombre de files d'attente créées dans le système.

Appel du compteur de file d'attente dans Nucleus SE
Cet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.

Prototype d'appel de service:
U8 NUSE_Queue_Count (void);

Paramètres:
Sont absents.

Valeur de retour:
Le nombre de files d'attente configurées dans l'application.

Implémentation du compteur de files d'attente dans Nucleus SE
L'implémentation de cet appel API est très simple: la valeur du symbole #define NUSE_QUEUE_NUMBER est retournée .

Structures de données


Les files d'attente utilisent cinq ou six structures de données (qui sont soit en RAM ou en ROM), qui sont des ensembles de tables (comme les autres objets Nucleus SE), dont le nombre et la taille correspondent au nombre de files d'attente dans l'application et aux paramètres sélectionnés.

Données du noyau dans la RAM


Ces données ont la structure suivante:

NUSE_Queue_Head [] est un tableau de pointeurs de type U8 , possède une entrée pour chaque file d'attente configurée et pointe vers la tête de la file d'attente de messages. Utilisé comme index d'adresse dans NUSE_Queue_Data [] (voir ci-dessous);
NUSE_Queue_Tail [] est un tableau de type U8 , possède une entrée pour chaque file d'attente configurée dans l'application et pointe vers la fin de la file d'attente de messages. Utilisé comme index d'adresse dans NUSE_Queue_Data [] (voir ci-dessous);
NUSE_Queue_Items [] est un tableau de type U8 , a une entrée pour chaque file d'attente configurée et est un compteur de messages dans la file d'attente. Ces données peuvent être considérées comme redondantes, car ces valeurs peuvent être obtenues via les index du début et de la fin de la file d'attente, cependant, le stockage du compteur simplifie le code;
NUSE_Queue_Blocking_Count [] - ce tableau de type U8 contient des compteurs du nombre de tâches suspendues sur chaque file d'attente. Ce tableau est créé uniquement si la prise en charge du verrouillage des tâches est activée.

Ces structures de données sont initialisées en zéros par la fonction NUSE_Init_Queue () au démarrage de Nucleus SE. C'est logique, car toutes les files d'attente sont créées vides (non utilisées).

Voici les définitions de ces structures dans le fichier nuse_init.c :

 RAM U8 NUSE_Queue_Head[NUSE_QUEUE_NUMBER]; RAM U8 NUSE_Queue_Tail[NUSE_QUEUE_NUMBER]; RAM U8 NUSE_Queue_Items[NUSE_QUEUE_NUMBER]; #if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Queue_Blocking_Count[NUSE_QUEUE_NUMBER]; #endif 

Données utilisateur RAM


L'utilisateur est responsable de fournir une zone RAM pour stocker chaque file d'attente. La taille de cette zone doit contenir un tableau de type ADDR , dans lequel chaque enregistrement correspond à un message dans la file d'attente

Données ROM


Ces données ont la structure suivante:

NUSE_Queue_Data [] - un tableau de type ADDR , a une entrée pour chaque file d'attente configurée et pointe vers la zone de données de la file d'attente (voir. Données RAM utilisateur);
NUSE_Queue_Size [] - un tableau de type U8 , a une entrée pour chaque file d'attente configurée et affiche le nombre maximal de messages que chaque file d'attente peut recevoir.

Ces structures de données sont déclarées et initialisées (statiquement) dans le fichier nuse_config.c :

 ROM ADDR *NUSE_Queue_Data[NUSE_QUEUE_NUMBER] = { /* addresses of queue data areas ------ */ }; ROM U8 NUSE_Queue_Size[NUSE_QUEUE_NUMBER] = { /* queue sizes ------ */ }; 

La quantité de mémoire pour les files d'attente


Comme tous les objets du noyau Nucleus SE, la quantité de mémoire nécessaire pour les files d'attente est facilement prévisible.

La quantité de données dans la ROM (en octets) pour toutes les files d'attente dans l'application peut être calculée comme suit:
NUSE_QUEUE_NUMBER * (taille de (ADDR) + 1)

La quantité de données du noyau dans la RAM (en octets) pour toutes les files d'attente dans l'application avec le verrouillage de tâche activé est calculée comme suit:
NUSE_QUEUE_NUMBER * 3

Si le verrouillage est désactivé:
NUSE_QUEUE_NUMBER * 4

La quantité de données utilisateur en RAM (en octets) pour la file d'attente avec l'index de file d'attente :
NUSE_Queue_Size [queue] * sizeof (ADDR)

Appels d'API non réalisés


Quatre appels d'API qui peuvent être trouvés dans Nucleus RTOS ne sont pas implémentés dans Nucleus SE:

Création de file d'attente


Cet appel API crée une file d'attente; dans Nucleus SE, cela n'est pas nécessaire, car les files d'attente sont créées statiquement.

Prototype d'appel de service:
STATUS NU_Create_Queue (file d'attente NU_QUEUE *, nom char *, VOID * start_address, UNSIGNED queue_size, OPTION message_type, UNSIGNED message_size, OPTION suspend_type);

Paramètres:

file d'attente - un pointeur vers une unité de contrôle fournie par l'utilisateur; il est utilisé pour gérer les files d'attente dans d'autres appels d'API;
nom - un pointeur vers un nom de file d'attente à 7 caractères avec un octet de fin nul;
start_address - adresse du début de la file d'attente;
message_type - type de message pris en charge par la file d'attente. Il peut prendre les valeurs NU_FIXED_SIZE ou NU_VARIABLE_SIZE ;
message_size - si la file d'attente prend en charge les messages d'une longueur fixe, ce paramètre définit la longueur exacte de chaque message, sinon, si la file d'attente prend en charge les messages de longueur variable, cette valeur est la longueur maximale du message;
suspend_type - détermine le type de suspension des tâches dans la file d'attente. Il peut prendre les valeurs NU_FIFO et NU_PRIORITY , qui désignent respectivement le principe de FIFO (First-In-First-Out) ou le principe de priorité de suspension des tâches.

Valeur de retour:

NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_QUEUE - pointeur nul vers le bloc de contrôle de file d'attente ( NULL ), ou le pointeur est déjà utilisé;
NU_INVALID_MEMORY - zone de mémoire non valide spécifiée dans start_address ;
NU_INVALID_MESSAGE - paramètre de type de message non valide;
NU_INVALID_SIZE - la file d'attente ne prend pas en charge les messages de cette longueur, ou la taille de la file d'attente et / ou la longueur des messages est 0;
NU_INVALID_SUSPEND - paramètre suspend_type non valide .

Supprimer la file d'attente


Cet appel d'API supprime la file d'attente créée précédemment. Nucleus SE n'en a pas besoin car les files d'attente sont créées statiquement et ne peuvent pas être supprimées.

Prototype d'appel de service:
STATUS NU_Delete_Queue (file d'attente NU_QUEUE *);

Paramètres:
queue - un pointeur vers un bloc de contrôle de file d'attente.

Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_QUEUE - pointeur de file d'attente non valide.

Pointeurs de file d'attente


Cet appel d'API crée une liste séquentielle de pointeurs vers toutes les files d'attente du système. Nucleus SE n'en a pas besoin car les files d'attente sont identifiées à l'aide d'un simple index, et non d'un pointeur.

Prototype d'appel de service:
UNSIGNED NU_Queue_Pointers (NU_QUEUE ** pointer_list, UNSIGNED maximum_pointers);

Paramètres:
pointer_list - pointeur vers un tableau de pointeurs NU_QUEUE . Ce tableau sera rempli de pointeurs vers les files d'attente créées dans le système;
maximum_pointers - le nombre maximum de pointeurs dans le tableau.

Valeur de retour:
Le nombre de pointeurs NU_QUEUE dans le tableau.

Mise en file d'attente (diffusion vers la file d'attente)


Cet appel d'API transmet le message à toutes les tâches suspendues dans la file d'attente qui attendent des messages de la file d'attente spécifiée. Cette fonctionnalité n'est pas implémentée dans Nucleus SE car elle ajoute de la redondance.

Prototype d'appel de service:
STATUS NU_Broadcast_To_Queue (file d'attente NU_QUEUE *, message VOID *, taille UNSIGNED, suspension UNSIGNED);

Paramètres:

queue - un pointeur vers un bloc de contrôle de file d'attente;
message - pointeur vers le message transmis;
size - le nombre d'éléments UNSIGNED dans le message. Si la file d'attente prend en charge les messages de longueur variable, ce paramètre doit être égal ou inférieur à la longueur de message prise en charge par la file d'attente. Si la file d'attente prend en charge les messages d'une longueur fixe, ce paramètre doit être égal à la longueur du message pris en charge par la file d'attente;
suspen - indique s'il faut suspendre la tâche appelante si la file d'attente est déjà pleine. Il peut s'agir de NU_NO_SUSPEND , NU_SUSPEND ou d'une valeur de délai d'expiration.

Valeur de retour:

NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_QUEUE - pointeur de file d'attente non valide;
NU_INVALID_POINTER - pointeur nul vers un message ( NULL );
NU_INVALID_SIZE - la longueur de message spécifiée n'est pas compatible avec la longueur spécifiée lors de la création de la file d'attente;
NU_INVALID_SUSPEND - tente de suspendre une tâche à partir d'un thread non associé à la tâche;
NU_QUEUE_FULL - il n'y a pas assez d'espace dans la file d'attente pour le message;
NU_TIMEOUT - la file d'attente est toujours pleine après l'expiration du délai;
NU_QUEUE_DELETED - la file d'attente a été supprimée alors que la tâche a été suspendue;
NU_QUEUE_RESET - La file d'attente a été réinitialisée lors de la suspension de la tâche.

Compatible avec Nucleus RTOS


Comme pour tous les autres objets Nucleus SE, mon objectif était de maximiser la compatibilité du code d'application avec Nucleus RTOS. Les files d'attente ne font pas exception et, du point de vue de l'utilisateur, elles sont implémentées 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 deviendra ainsi plus compréhensible et plus efficace en termes de quantité de mémoire requise. Sinon, les appels d'API Nucleus RTOS peuvent être portés presque directement vers Nucleus SE.

Identificateurs d'objet


Dans Nucleus RTOS, tous les objets sont décrits par une structure de données (unités de contrôle) qui a un type de données spécifique. Un pointeur vers cette unité de contrôle sert d'identifiant pour la file d'attente. 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_QUEUE comme l'équivalent de U8 , une variable (pas un pointeur) de ce type sert d'identifiant de file d'attente. 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 la dénomination des files d'attente. Ces noms sont utilisés uniquement pour le débogage. Je les ai exclus de Nucleus SE pour économiser de la mémoire.

Taille et type du message


Dans Nucleus RTOS, une file d'attente peut être configurée pour traiter les messages composés d'un nombre illimité d' éléments non signés . Dans Nucleus SE, les files d'attente sont simplifiées et ne prennent en charge que les messages de type ADDR uniques. Les canaux de données de Nucleus SE sont un peu plus flexibles et peuvent être une alternative utile aux files d'attente dans certains cas. Les chaînes seront couvertes dans les deux prochains articles de cette série.

Nucleus SE prend également en charge les files d'attente de messages de longueur variable, qui spécifient uniquement la longueur maximale des messages lors de la création. Les longueurs de message variables ne sont pas prises en charge par Nucleus SE

Taille de la file d'attente


Dans Nucleus SE, le nombre maximal de messages dans une file d'attente est de 256, car toutes les variables et constantes sont de type U8 . Nucleus RTOS n'a pas de telles limitations.

Appels d'API non réalisés


Nucleus RTOS prend en charge dix appels de gestion de file d'attente. Parmi ceux-ci, quatre ne sont pas implémentés dans Nucleus SE. Les détails de ces appels, ainsi que les raisons d'une telle décision, peuvent être trouvés dans cet article ci-dessus, dans la section "Appels d'API non réalisés".

Le prochain article traitera des canaux de transmission 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.

Source: https://habr.com/ru/post/fr432804/


All Articles