Toute la vérité sur RTOS. Article # 14. Sections de mémoire: introduction et services de base



Des sections de la mémoire ont été mentionnées plus tôt dans l'un des articles précédents (# 6), où une comparaison a été faite avec la fonction standard du langage C malloc () . Une partition est une région de mémoire obtenue à partir d'un pool de partitions (pool de mémoire). Le partage de mémoire offre un moyen flexible d'allouer de façon fiable et déterministe et de libérer de la mémoire.

Articles précédents de la série:
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.

Utilisation de sections


Dans Nucleus SE, les pools de partitions sont configurés au moment de la création. Une seule application peut avoir jusqu'à 16 pools de partitions. S'ils ne sont pas configurés, les structures de données et les appels de service liés à ces pools ne seront pas inclus dans l'application.

Un pool de partitions est une zone mémoire divisée en un certain nombre de blocs de taille fixe. Le développeur a un contrôle total sur la taille et le nombre de partitions dans chaque pool. Les tâches peuvent demander des sections de mémoire allouées et recevoir un pointeur vers la zone de stockage et ne doivent pas écrire de données en dehors de la section allouée. Une section peut être libérée par n'importe quelle tâche lors du passage d'un pointeur vers une fonction API. Une demande d'allocation d'une partition en l'absence de partitions libres peut entraîner une erreur ou une suspension de la demande, selon les paramètres d'appel API sélectionnés et la configuration de Nucleus SE.

Configuration de partitions de mémoire


Nombre de pools de partitions


Comme pour la plupart des objets Nucleus SE, la configuration du pool de partitions se fait principalement à l'aide de la directive #define dans nuse_config.h . Le paramètre principal est NUSE_PARTITION_POOL_NUMBER , qui détermine le nombre de pools de partitions définis dans l'application. La valeur par défaut est 0 (c'est-à-dire que les pools de partitions ne sont pas utilisés), le développeur peut définir n'importe quelle valeur de 0 à 16. D'autres valeurs entraîneront une erreur de compilation, qui a été détectée lors de la vérification dans nuse_config_check.h (elle est incluse dans nuse_config.c , et , donc, compile avec ce module), ce qui conduit à la compilation de la directive #error .

Le choix d'une valeur différente de zéro est un moyen prioritaire d'activer les pools de partitions. Cela conduit à la définition des structures de données et à l'attribution de la taille appropriée. Les structures de données dans la ROM doivent être initialisées avec les valeurs appropriées qui décrivent chaque pool de partitions. Plus de détails sur les structures de données seront dans le prochain article. Cette sélection active également 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 pools de partitions, ceux-ci incluent:

NUSE_PARTITION_ALLOCATE
NUSE_PARTITION_DEALLOCATE
NUSE_PARTITION_POOL_INFORMATION
NUSE_PARTITION_POOL_COUNT

Par défaut, ils sont tous définis sur FALSE , désactivant ainsi chaque appel de service et empêchant l'inclusion d'un code d'implémentation. Pour configurer les pools de partitions dans l'application, 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:



Si la fonction API Partition Pools est activée, mais que les pools ne sont pas configurés, une erreur de compilation se produit (à l'exception de NUSE_Partition_Pool_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 l'utilitaire du pool de partitions


Nucleus RTOS prend en charge sept appels d'utilitaires liés aux pools de partitions, qui offrent les fonctionnalités suivantes:

Description fonctionnelleNucleus RTOSNucleus SE
Sélection de sectionNU_Allocate_Partition ()NUSE_Partition_Allocate ()
Communiqué de sectionNU_Deallocate_Partition ()NUSE_Partition_Deallocate ()
Fournir des informations
Ă  propos d'un pool de partitions particulier
NU_Partition_Pool_Information ()NUSE_Partition_Pool_Information ()
Renvoie la valeur de la quantité (actuellement) configurée
pools d'applications
NU_Established_Partition_Pools ()NUSE_Partition_Pool_Count ()
Ajout (création) d'un nouveau pool de partitions à l'applicationNU_Create_Partition_Pool ()Non implémenté.
Modification (suppression) d'un pool de partitions d'une applicationNU_Delete_Partition_Pool ()Non implémenté.
Renvoyer des pointeurs vers tous les pools de partitions existants dans l'applicationNU_Partition_Pool_Pointers ()Non implémenté.

La mise en œuvre de chaque appel sera discutée en détail.

Il convient de noter que ni Nucleus RTOS ni Nucleus SE n'ont de fonction de redémarrage. Cela se fait exprès. Très souvent, une tâche alloue une section et transmet un pointeur à une autre tâche (qui peut ensuite la libérer). Si vous rechargez le pool de partitions, toutes les partitions seront marquées comme inutilisées, cependant, il n'existe aucun mécanisme pour surveiller et notifier toutes les tâches pouvant utiliser des partitions.

Services de partition et de libération


Les opérations fondamentales avec les pools de partitions sont l'allocation des partitions dans le pool (c'est-à-dire marquer la partition comme utilisée et renvoyer son adresse) et libérer la partition (c'est-à-dire que la partition est marquée comme non utilisée). Nucleus RTOS et Nucleus SE fournissent deux appels d'API de base pour ces opérations, qui sont décrits ci-dessous.

Sélection de section


L'appel de l'API RTOS Nucleus pour allouer une partition est très flexible, ce qui permet aux développeurs de suspendre les tâches pendant une période indéfinie ou sans délai si l'opération ne peut pas être terminée immédiatement, par exemple, lorsque vous essayez d'allouer une partition à partir d'un pool dans lequel toutes les partitions sont déjà distribuées. Nucleus SE fournit le même service, seules les tâches de pause sont facultatives et aucun délai d'attente n'est implémenté.

Appel Ă  la partition de l'API Nucleus RTOS


Prototype d'appel:

STATUS NU_Allocate_Partition (pool NU_PARTITION_POOL *, VOID ** return_pointer, suspension UNSIGNED);

Valeur de retour:

NU_SUCCESS - l'appel s'est terminé avec succès;
NU_NO_PARTITION - aucune section n'est disponible;
NU_INVALID_POOL - pointeur de pool de partitions non valide;
NU_INVALID_POINTER - a passé un pointeur nul aux données retournées ( NULL );
NU_INVALID_SUSPEND - une tentative de suspension d'une tâche a été effectuée à partir d'un thread non associé à la tâche;
NU_TIMEOUT - aucune partition n'est disponible, même après suspension pour la période d'attente spécifiée;
NU_POOL_DELETED - Le pool de partitions a été supprimé lorsque la tâche a été suspendue.

Appel de l'API Nucleus SE pour mettre en surbrillance une partition


Cet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.

Prototype d'appel:

STATUS NUSE_Partition_Allocate (pool NUSE_PARTITION_POOL, ADDR * return_pointer, U8 suspend);

Paramètres:

pool - index (ID) du pool de partitions utilisé;
return_pointer - pointeur vers une variable de type ADDR , qui prend l'adresse de la section sélectionnée;
suspend - paramètre pour suspendre la tâche; il peut prendre les valeurs NUSE_NO_SUSPEND ou NUSE_SUSPEND .

Valeur de retour:

NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_NO_PARTITION - aucune section n'est disponible;
NUSE_INVALID_POOL - index de pool de partitions non valide;
NUSE_INVALID_POINTER - a passé un pointeur nul aux données retournées ( NULL );
NUSE_INVALID_SUSPEND: une tentative de suspension d'une tâche a été effectuée à partir d'un thread qui n'était pas associé à la tâche ou lorsque les API de verrouillage ont été désactivées.

Implémentation de l'allocation de partition dans Nucleus SE


Le code de fonction API NUSE_Partition_Allocate est sélectionné à l'aide de la compilation conditionnelle après vérification des paramètres, selon que l'appel API à bloquer (suspendre les tâches) est activé ou non. Ci-dessous, nous examinerons séparément ces deux options.

Si les appels de blocage sont désactivés, l'appel d'API est assez simple:



Tout d'abord, la disponibilité des partitions gratuites est vérifiée. S'il n'y a pas de telles partitions, une erreur est renvoyée ( NUSE_NO_PARTITION ). Ensuite, il y a une énumération des sections, au cours de laquelle les premiers octets sont vérifiés pour des valeurs nulles (ce qui indique que la section n'est pas utilisée). Lorsqu'une telle partition est trouvée, elle se voit attribuer l'indicateur «utilisé», qui inclut l'index du pool de partitions (voir «Libérer la partition» ci-dessous), et renvoie un pointeur sur l'octet suivant (le début de la zone de données réelles). Des explications sur les structures de données des pools de partitions seront présentées dans l'article suivant de la section Structures de données.

Si le verrouillage est activé, le code de cet appel API devient un peu plus compliqué:



Le code est enfermé dans une boucle do ... while , qui continue de s'exécuter tant que le paramètre de pause est NUSE_SUSPEND .

Si aucune partition n'est disponible et que le paramètre de pause est NUSE_NO_SUSPEND , l'appel d'API s'arrête et renvoie NUSE_NO_PARTITION . Si le paramètre de pause a été défini sur NUSE_SUSPEND , la tâche se met en pause. Lors du retour (par exemple, lorsqu'une tâche reprend), la valeur de retour de NUSE_SUCCESS indique que la tâche a été reprise car la section mémoire a été libérée et le code retourne au début de la boucle. Comme il n'y a pas de fonctions API pour recharger les pools de partitions, les tâches ne peuvent pas être reprises pour d'autres raisons, mais pour la stabilité du blocage d'autres types d'objets, le processus de validation NUSE_Task_Blocking_Return [] est conservé.

Communiqué de section


La sortie de la section dans Nucleus RTOS et Nucleus SE la rend à nouveau disponible. Avant la publication, il ne vérifie pas si cette section est utilisée par une tâche ou non, le programmeur d'application en est responsable. Seul un pointeur vers une zone de données est requis pour libérer une section.

Appel de l'API Nucleus RTOS Ă  la partition gratuite


Prototype d'appel:

STATUS NU_Deallocate_Partition (partition VOID *);

Paramètres:

partition - un pointeur vers la zone de données (retournée par la fonction NU_Allocate_Partition () ) de la partition à libérer;

Valeur de retour:

NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_POINTER - Pointeur de section NULL ou n'indique pas une section valide utilisée.

Appel de l'API Nucleus SE pour libérer la partition


Cet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.

Prototype d'appel:

STATUS NUSE_Partition_Deallocate (partition ADDR);

Paramètres:

partition - un pointeur vers la zone de données (retournée par la fonction NUSE_Partition_Allocate () ) de la partition à libérer

Valeur de retour:

NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_POINTER - le pointeur de section est nul ( NULL ) ou n'indique pas une section valide utilisée

Implémentation


Au lieu d'implémenter à l'aide des fonctions API bloquantes et non bloquantes, la fonction NUSE_Partition_Deallocate () contient simplement une section compilée conditionnellement qui est responsable du déverrouillage des tâches. Ce code implémente la libération des sections:



Tout d'abord, l'index de section est extrait de l'octet d'état. Ensuite, l'état de la partition passe à "inutilisé", le compteur des partitions utilisées diminue et la fonction signale la réussite de l'opération.

Si le verrouillage est activé, le code suivant est utilisé pour reprendre les tâches en attente du pool de partitions disponible:



Si des tâches ont été bloquées lors de l'allocation de partitions dans ce pool, la première table reprend.

Dans le prochain article, nous parlerons des appels d'API supplémentaires liés aux partitions de mémoire, ainsi que des structures de données associé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.

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


All Articles