Files d'attente dans Nucleus SE : Introduction et appels de service de base
Voir la série RTOS Revealed
Les files d'attente ont été introduites dans un article précédent. Elles fournissent un moyen plus flexible de passer des messages simples entre tâches que les boîtes aux lettres.
Utilisation des files d'attente
Dans Nucleus SE, les files d'attente sont configurées à la compilation. Un maximum de 16 files peut être défini pour une application. Si aucune file n'est configurée, le RTOS omet toutes les structures de données et le code API associés, gardant le binaire léger.
Une file d'attente est simplement un tableau d'emplacements de stockage, chacun assez grand pour contenir un seul élément de données ADDR. L'accès est synchronisé pour que plusieurs tâches puissent mettre en file et défiler des messages en sécurité. Les tâches peuvent écrire dans une file jusqu'à ce que tous les emplacements soient pleins, et lire depuis une file dans un ordre premier entré, premier sorti (FIFO). Les tentatives d'envoi vers une file pleine ou de réception depuis une file vide déclenchent une erreur ou une suspension de tâche, selon les options API sélectionnées et la configuration Nucleus SE.
Files d'attente vs Tuyaux
Nucleus SE supporte aussi les tuyaux (pipes), qui diffèrent principalement par la taille du message. Alors qu'une file transmet un seul ADDR (typiquement un pointeur), un tuyau transporte un bloc d'octets de longueur variable ; la taille du bloc est fixée à la configuration. Les tuyaux sont discutés en profondeur dans un futur article.
Configuration des files d'attente
Nombre de files d'attente
La configuration des files est contrôlée par des instructions #define dans nuse_config.h. Le réglage clé est NUSE_QUEUE_NUMBER, qui détermine combien de files sont activées. La valeur par défaut est 0 (pas de files). Vous pouvez la définir à toute valeur de 0 à 16 ; une valeur hors plage déclenche une erreur #error à la compilation produite par nuse_config_check.h.
Définir NUSE_QUEUE_NUMBER sur une valeur non-nulle active le sous-système de files, allouant les structures de données nécessaires et activant les appels API associés.
Activations des API
Chaque fonction API de file a un symbole #define d'activation dans nuse_config.h :
NUSE_QUEUE_SEND NUSE_QUEUE_RECEIVE NUSE_QUEUE_JAM NUSE_QUEUE_RESET NUSE_QUEUE_INFORMATION NUSE_QUEUE_COUNT
Par défaut, toutes sont définies sur FALSE, désactivant les appels de service correspondants. Pour utiliser une API particulière, définissez son symbole sur TRUE. Activer une API sans files configurées (sauf NUSE_Queue_Count(), toujours autorisée) résulte en une erreur à la compilation. Si une API est appelée dans du code qui n'a pas été activé, une erreur à l'édition de liens se produit car l'implémentation est omise.
#define NUSE_QUEUE_NUMBER 0 /* Nombre de files dans le système – 0‑16 */ /* Activateurs d'appels de service */ #define NUSE_QUEUE_SEND FALSE #define NUSE_QUEUE_RECEIVE FALSE #define NUSE_QUEUE_JAM FALSE #define NUSE_QUEUE_RESET FALSE #define NUSE_QUEUE_INFORMATION FALSE #define NUSE_QUEUE_COUNT FALSE
Appels de service des files d'attente
Nucleus RTOS offre dix appels de service liés aux files, dont six sont implémentés dans Nucleus SE. Ils fournissent les fonctionnalités suivantes :
- Envoyer un message — NUSE_Queue_Send()
- Recevoir un message — NUSE_Queue_Receive()
- Insérer un message en tête — NUSE_Queue_Jam()
- Réinitialiser une file — NUSE_Queue_Reset()
- Interroger informations file — NUSE_Queue_Information()
- Obtenir le nombre de files configurées — NUSE_Queue_Count()
- Appels restants (créer, supprimer, énumérer, diffuser) non disponibles dans Nucleus SE.
L'implémentation de chaque API est discutée en détail dans les sections suivantes.
Services d'écriture et de lecture
Les opérations de base sur une file sont l'écriture (envoi) et la lecture (réception). L'écriture en tête de file s'appelle « jammer ». Nucleus RTOS et Nucleus SE exposent chacun trois appels API de base pour ces actions.
Écriture dans une file
L'API RTOS NU_Send_To_Queue() est hautement flexible, permettant suspension indéfinie ou timeout si la file est pleine. Nucleus SE offre la même fonction mais la suspension est optionnelle et les timeouts ne sont pas supportés. RTOS supporte aussi une opération de diffusion, indisponible dans SE.
API RTOS : NU_Send_To_Queue()
Prototype :
STATUS NU_Send_To_Queue(NU_QUEUE *queue, VOID *message, UNSIGNED size, UNSIGNED suspend);
Paramètres :
- queue — pointeur vers le bloc de contrôle de file fourni par l'utilisateur
- message — pointeur vers les données à envoyer
- size — nombre d'éléments UNSIGNED ; doit correspondre à la taille de message de la file
- suspend — NU_NO_SUSPEND, NU_SUSPEND, ou une valeur de timeout
Codes de retour incluent NU_SUCCESS, NU_QUEUE_FULL, NU_TIMEOUT, et divers codes d'erreur pour pointeurs invalides ou état de file.
API SE : NUSE_Queue_Send()
Prototype :
STATUS NUSE_Queue_Send(NUSE_QUEUE queue, ADDR *message, U8 suspend);
Paramètres :
- queue — index de file (ID)
- message — pointeur vers la valeur ADDR à enfiler
- suspend — NUSE_NO_SUSPEND ou NUSE_SUSPEND
Les valeurs de retour mirent la fonction RTOS mais reflètent le comportement de blocage limité de SE.
Vue d'ensemble de l'implémentation
Quand le blocage est désactivé, la routine vérifie simplement s'il y a de l'espace et soit écrit la valeur, soit retourne NUSE_QUEUE_FULL. Avec le blocage activé, la fonction boucle, suspendant la tâche si la file est pleine jusqu'à ce qu'un espace devienne disponible ou qu'une réinitialisation survienne. L'implémentation utilise NUSE_Queue_Blocking_Count pour suivre les tâches bloquées et NUSE_Task_Blocking_Return pour les reprendre une fois un créneau ouvert.
if (NUSE_Queue_Items[queue] == NUSE_Queue_Size[queue]) { return_value = NUSE_QUEUE_FULL; } else { NUSE_Queue_Data[queue][NUSE_Queue_Head[queue]++] = *message; if (NUSE_Queue_Head[queue] == NUSE_Queue_Size[queue]) NUSE_Queue_Head[queue] = 0; NUSE_Queue_Items[queue]++; return_value = NUSE_SUCCESS; }
do { if (NUSE_Queue_Items[queue] == NUSE_Queue_Size[queue]) { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_QUEUE_FULL; } else { NUSE_Queue_Blocking_Count[queue]++; NUSE_Suspend_Task(NUSE_Task_Active, (queue << 4) | NUSE_QUEUE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) suspend = NUSE_NO_SUSPEND; } } else { NUSE_Queue_Data[queue][NUSE_Queue_Head[queue]++] = *message; if (NUSE_Queue_Head[queue] == NUSE_Queue_Size[queue]) NUSE_Queue_Head[queue] = 0; NUSE_Queue_Items[queue]++; if (NUSE_Queue_Blocking_Count[queue] != 0) { U8 index; NUSE_Queue_Blocking_Count[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_SUCCESS; NUSE_Wake_Task(index); break; } } } return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } } while (suspend == NUSE_SUSPEND);
La boucle continue jusqu'à ce qu'un message soit enfilé avec succès ou que la tâche soit débloquée par une réinitialisation. L'implémentation assure un accès thread-safe et un réveil efficace des consommateurs bloqués.
Embarqué
- Serrures à came (cam locks) expliquées : comment elles sécurisent armoires discrètement
- Qu'est-ce qu'une vis à œil (eye screw) ? Guide professionnel conception et usages
- Comprendre les œillets : types, utilisations et protection de vos équipements
- Acier inoxydable expliqué : composition, production et impact mondial
- Fondamentaux C# : Entrées et sorties essentielles
- Boîtes aux lettres dans Nucleus SE : Guide pratique de configuration et d'utilisation
- Sémaphores dans Nucleus RTOS : Services utilitaires et structures de données
- Sémaphores dans Nucleus SE : Vue d'ensemble, configuration et API essentielles
- Maîtriser les groupes de drapeaux d'événement : Services utilitaires et structures de données dans Nucleus RTOS/SE