Identificateurs de tâche
Vous devez être en mesure d'identifier chaque tâche du système. Cette exigence est importante pour les autres objets du noyau, mais il y a quelques nuances dans les tâches qui correspondent au sujet de cet article.

Les développeurs de RTOS utilisent différentes approches pour identifier les tâches, mais quatre stratégies générales peuvent être distinguées:
- La tâche est identifiée à l'aide d'un pointeur sur son «bloc de contrôle». Les pointeurs sont toujours uniques et également pratiques à utiliser, car l'accès à l'unité de contrôle est requis pour de nombreux appels API. Cela implique que toutes les données de tâche sont stockées dans la mémoire vive (RAM), ce qui peut être inefficace. Un pointeur prend généralement environ 32 bits de mémoire.
- Une tâche peut être définie à l'aide d'un "numéro d'index" arbitraire. Cette valeur peut être utile lors de l'octroi de l'accès aux enregistrements de certaines tables. Un tel identifiant peut occuper huit bits de mémoire ou moins, en fonction des limitations du nombre de tâches prises en charge par le RTOS.
- Certains RTOS n'autorisent qu'une seule tâche par niveau de priorité et utilisent donc la priorité pour identifier de manière unique une tâche. Cela signifie que la priorité de la tâche ne peut pas être modifiée. Cette approche est une variante de l'approche précédente.
- Les tâches peuvent avoir des noms qui sont des chaînes de caractères. Cela peut être utile pour le débogage, mais il est peu probable qu'il soit un moyen efficace d'identifier de manière unique une tâche. Les RTOS qui prennent en charge la dénomination des tâches ont généralement un identifiant supplémentaire (tel qu'un pointeur) utilisé par les appels d'API, etc. Pour la plupart des systèmes intégrés, les noms de texte sont en surcharge; un bon débogueur vous permet de les appeler localement sur l'hôte.
Articles précédents de la série:
Article # 3. Tâches et planificationArticle # 2. RTOS: Structure et mode temps réel
Article # 1. RTOS: introduction.
Changement de contexte
La commutation de contexte est le processus de transfert de contrôle d'une tâche à une autre. Ce sujet mérite d'être approfondi, car le fonctionnement du changement de contexte est un principe fondamental du RTOS.
Qu'est-ce qu'une tâche?
Nous savons qu'une tâche est un programme quasi indépendant qui partage le temps processeur avec un certain nombre d'autres tâches sous le contrôle de RTOS. Mais vous devez penser à ce qui caractérise vraiment la tâche.
Ensemble de registres
Une tâche est finalement un ensemble unique de valeurs de registre de processeur. Ils sont soit chargés dans les registres du processeur (c'est-à-dire que la tâche est en cours), soit stockés quelque part jusqu'à l'heure d'exécution planifiée. Dans un monde idéal, un processeur central aurait plusieurs ensembles de registres et chacun pourrait être affecté à une tâche distincte. Cela a été mis en œuvre pour des occasions spéciales. Il y a de nombreuses années, la série Texas Instruments TI 9900 avait de nombreux jeux de registres pour chaque tâche, mais ils étaient implémentés dans la mémoire principale, ce qui limitait les performances. L'architecture SPARC (précédemment utilisée sur les systèmes de bureau Unix) prend en charge de nombreux ensembles de registres dans la «structure en anneau», mais le nombre d'ensembles est toujours limité.
Données internes
La tâche aura probablement sa propre pile, dont la taille peut être définie séparément pour chaque tâche ou peut être un paramètre global pour toutes les tâches du système. Ceci, avec les registres, fournit un stockage de données pour des tâches spécifiques. Il peut y avoir d'autres zones de mémoire pour stocker des données pour une tâche spécifique.
Ressources partagées
Pratiquement toutes les ressources peuvent être partagées entre les tâches. Le code peut être général: soit certaines fonctions, soit l'intégralité du code de tâche. Il est nécessaire de s'assurer que le code est réentrant, tout d'abord, les variables statiques ne doivent pas être utilisées (spécifiées comme statiques ou juste en dehors de la fonction). Soyez prudent avec les modules de bibliothèque standard qui ne sont pas destinés à une utilisation intégrée; ils ont généralement beaucoup de fonctions peu fiables.
Le partage de données est également possible, mais un contrôle d'accès minutieux est nécessaire. Idéalement, une seule tâche est le «propriétaire» des données à un moment donné.
Comment garder le contexte
Lorsqu'une tâche est replanifiée (c'est-à-dire qu'elle cesse d'être actuelle), son ensemble de registres doit être enregistré quelque part. Il y a au moins deux possibilités:
- Les registres peuvent être stockés dans une table spéciale pour les tâches. Peut faire partie d'un bloc de contrôle des tâches (TCB). La taille est une valeur prévisible et constante (pour une architecture CPU spécifique).
- Les registres peuvent être insérés dans la pile des tâches. Cela nécessite l'allocation d'un espace de pile supplémentaire suffisant et le stockage du pointeur (éventuellement dans le TCB).
Le choix du mécanisme dépend des caractéristiques d'un RTOS particulier et du processeur cible. Certains périphériques (généralement 32 bits) peuvent accéder efficacement à la pile; le reste (par exemple, 8 bits) peut être plus optimal lorsque vous travaillez avec des tables.
Création de tâche dynamique
L'aspect principal de l'architecture RTOS est que le RTOS est soit «statique» soit «dynamique».
Lors de l'utilisation d'un RTOS statique, tout est déterminé lors de la construction de l'application, notamment le nombre de tâches dans le système. Il s'agit d'une solution logique pour les applications intégrées, qui ont généralement des fonctionnalités limitées.
Dynamic RTOS lance une tâche (qui peut être une tâche «principale» spécialisée) et crée et supprime également d'autres tâches selon les besoins. Cela permet au système de s'adapter aux exigences changeantes et est un analogue plus proche du système de bureau, qui se comporte de cette façon. La vue statique / dynamique s'applique également aux autres objets du noyau.
Exigence de création de tâche dynamique
Cette fonctionnalité est incluse dans la plupart des RTOS commerciaux. Cependant, seule une petite partie des applications a vraiment besoin d'un mode de fonctionnement dynamique. Très souvent, le système démarre, crée toutes les tâches nécessaires (et autres objets), puis ne crée et ne détruit plus le code d'application. La possibilité de créer des tâches dynamiques est devenue une formalité. Un fournisseur l'a présenté, tous les autres ont emboîté le pas.
Il est à noter que la norme OSEK / VDX nécessite une architecture statique, même si cela peut s'appliquer à des applications assez complexes. Le résultat de ces exigences est l'impossibilité d'implémenter OSEK / VDX avec un wrapper, une couche intermédiaire au-dessus d'un RTOS régulier (dynamique).
Pièges de la création de tâches dynamiques
Il y a plusieurs problèmes avec le mode de fonctionnement dynamique qui peuvent être troublants.
Premièrement, le système devient plus complexe, ce qui signifie que pour les structures de données décrivant les tâches (TCB), des informations supplémentaires sont nécessaires. En règle générale, ils sont mis en œuvre sous la forme de listes bidirectionnelles, ce qui entraîne des coûts associés à la quantité de mémoire.
Toutes les données décrivant la tâche doivent être stockées dans la RAM. Ceci est inefficace, car la plupart d'entre eux peuvent simplement être des éléments de données persistants copiés à partir de la ROM. De plus, sur les processeurs d'un niveau inférieur (microcontrôleurs), il peut ne pas obtenir de RAM.
Le plus inquiétant est probablement la possibilité d'une pénurie imprévisible de ressources, qui peut conduire à l'incapacité de créer de nouveaux objets. Étant donné que l'essence d'un système en temps réel est sa prévisibilité, cela est inacceptable. Par conséquent, il faut être prudent lors de l'utilisation de la création de tâches dynamiques (et d'autres objets).
Interruptions
Il est possible qu'un système embarqué en temps réel puisse être implémenté sans utiliser d'interruptions, mais ce n'est pas typique.
Interruptions et noyau
Lorsque vous utilisez RTOS, un gestionnaire d'interruption (ISR) est rendu aussi facile que possible pour «voler» le temps minimum du processeur des tâches planifiées. Souvent, un périphérique peut simplement être réparé et toute tâche requise sera mise en file d'attente pour le traitement. De plus, il est difficile de parler de manière générale des interruptions et de leur interaction avec les noyaux, simplement parce qu'elles varient considérablement. D'une part, le développeur RTOS peut s'assurer que les interruptions ne se rapportent pas du tout au noyau, et le programmeur devra s'assurer que le planificateur de tâches n'est pas surchargé, en utilisant beaucoup de temps processeur dans l'ISR. D'un autre côté, le RTOS peut contrôler entièrement l'ensemble du sous-système d'interruption. Aucune des approches décrites n'est bonne ou mauvaise, elles sont juste différentes.
Enregistrement du contexte
Les ISR doivent toujours maintenir un «contexte» afin que le code interruptible ne soit pas affecté par les calculs ISR. Dans un système implémenté sans RTOS, il s'agit simplement de sauvegarder les registres utilisés par l'ISR (généralement sur la pile) et de les restaurer avant de revenir. Certains processeurs ont une pile ISR dédiée, tandis que d'autres utilisent simplement la même pile que le code d'application.
Lorsque vous utilisez RTOS, l'approche peut être exactement la même. De la même manière, la pile utilisée par l'ISR peut être «empruntée» à la tâche en cours, ou il peut s'agir d'une autre pile allouée pour les interruptions. Certains cœurs implémentent cette fonctionnalité, même si le processeur lui-même ne prend pas en charge la pile d'interruptions. La situation est compliquée si l'ISR effectue un appel d'API qui affecte le planificateur de tâches. Cela peut entraîner l'interruption de revenir à une autre tâche à partir de celle qui a été démarrée lorsque l'interruption s'est produite.
Interruptions et planificateur
Il existe plusieurs circonstances dans lesquelles le code d'exécution ISR peut revenir à une autre tâche:
- ISR peut attribuer une priorité plus élevée à une tâche déjà terminée, plutôt qu'à la tâche actuelle, si le planificateur de tâches prioritaires est utilisé.
- ISR peut suspendre la tâche en cours.
- En utilisant le Time-Slice Scheduler (TS), le gestionnaire d'interruption du temporisateur système contrôlera les intervalles de temps et pourra appeler le planificateur si nécessaire.
Minuterie d'horloge (Tick Clock)
Dans les systèmes embarqués, l'utilisation d'une «horloge» périodique (tranche de temps) est souvent trouvée. Dans certains RTOS, c'est un composant requis. En règle générale, la présence d'une horloge est facultative et son absence empêche simplement la disponibilité de certains services. Le gestionnaire d'interruption du minuteur fournit généralement quatre fonctionnalités:
- Si un planificateur d'intervalles de temps est utilisé, le gestionnaire d'interruption de la minuterie contrôlera le compteur de temps et planifiera une nouvelle tâche chaque fois que le temps sera écoulé.
- Fournit une prise en charge du temps système. Il s'agit principalement d'une variable 32 bits qui est incrémentée par une minuterie et peut être prédéfinie ou demandée par des tâches.
- Si le RTOS fournit des applications avec des temporisateurs, il sera pris en charge par un gestionnaire d'interruption de temporisateur qui sera responsable de l'expiration et de la reprogrammation.
- Si le RTOS prend en charge les délais d'expiration pour bloquer les appels d'API ou que les tâches peuvent être en veille, ces intervalles de temps seront pris en charge par le gestionnaire d'interruption du minuteur.
Lorsque nous avons travaillé sur notre propre système d'exploitation OSRV MAX en temps réel (articles déjà publiés à ce sujet), notre équipe a «découvert» le blog de Colin Walls, un expert en microélectronique et firmware de Mentor Graphics. Les articles semblaient intéressants, les traduisaient eux-mêmes, mais afin de ne pas "écrire sur la table", ils ont décidé de publier. J'espère qu'ils vous seront également utiles. Si c'est le cas, nous prévoyons de publier tous les articles traduits de la série.
À 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: blogs.mentor.com/colinwalls, e-mail: colin_walls@mentor.com
Lisez les
premier, deuxième et
troisième articles de la série publiée précédemment.