polycopié
Transcription
polycopié
Systèmes temps réel et systèmes embarqués Linux temps réel : Xenomai Jacques Gangloff, Loı̈c Cuvillon 12 février 2008 Plan Plan Table des matières 1 Système d’exploitation temps réel 1.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 OS temps réel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 2 2 Linux n’est pas temps réel 2.1 OS à usage général (GPOS) . . . . . . . . . . . . . . . . . . . . . . . 2.2 Préemption et latence . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 5 3 Vers un Linux temps réel 3.1 Evolution de la préemption du noyau . . . . . . . . . . . . . . . . . . 3.2 Approche dual-kernel (co-noyau) . . . . . . . . . . . . . . . . . . . . 9 9 11 4 Xenomai 4.1 ADEOS : virtualisation (co-noyau) . . . . . . . . . . . . . . . . . . . 4.2 Programmation temps réel avec Xenomai . . . . . . . . . . . . . . . 12 12 15 5 Annexe : aperçu de l’API Native 18 Références – Understanding the Linux Kernel, Edition O’Reilly, 3ème édition – Xenomai Documentation – Cours – [1] Programmation temps-réel, Introduction par Daniel Rossier – [2] Linux temps réel par Jen-Marie Gillot (enst Bretagne) – [3] Real Time in Embedded Linux Systems, Free Electrons – Rapport – Linux Scheduler Latency de Clark Williams, Red Hat – A Quantitative Comparison of Realtime Linux Solutions de Markus Franke 1 Acronymes – API : Application Programming Interface – BD : Base de données – INT : Interruption – IPC : Inter Process Communication – IRQ : Interrupt ReQuest – ISR : Interrupt Service Routine – TSC : Time Stamp Counter – OS : système d’exploitation (Operating System) – RTOS : Real Time OS – GPOS : General Purpose OS 1 Système d’exploitation temps réel 1.1 Définition Système temps réel Définition – logiciel/hardware permettant de remplir des tâches dans un environnement imposé en respectant des contraintes de temps et débit – traitement d’évènements asynchrones sans pertes – traitement à échéance temporelle prédéfinie Caractéristiques – déterminisme logique (fonctionnel) même réponse pour un même vecteur d’entrée – déterminisme temporel (dynamique) respect des contraintes temporelles → un système temps réel doit être prédictible – latence (tps de réveil d’une tâche à une INT) et ses variations (jitter) connues Système temps réel Classification – Temps réel strict ou dure (Hard-realtime) – toutes les échéances doivent être garanties ; – destruction ou blocage possible du système en cas de dépassement ; – résolution actuelle de l’ordre de la µs ; – OS dédiés (VxWorks, RTLinux POSIX 1003.13,..) 2 – Temps réel mou (Soft-realtime) – quelques échéances peuvent être dépassées, avec perte de qualité ; – les OS actuelles gèrent les tâches temps réel molles (Linux POSIX-1003.1b,...) ; – exemple : décodage d’un mp3 (si charge trop importante du système = courte interruption sonore) 1.2 OS temps réel OS temps réel Fonctionnalités d’un RTOS – ne diffère pas fondamentalement d’un OS standard – mais OS plus simple et réduite (micro-kernel : embarqué, API réduite) – programmation de tâches périodiques ou non avec IPC ; – ordonnancement strict des tâches temps réel (priorités) ; – temps de latence minimal (noyau préemptible) Tâches temps réel Communication(IPC) Synchronisation/ Utilisation services Ordonnanceur ISR Activation INT Périphériques CPU Temps Capteur Monde extérieur I/O Actionneur −− Procédé OS temps réel : Exemples RTOS commerciaux – LynxOS http ://www.lynuxworks.com – pSOS+ http ://www.windriver.com (rachat) – Qnx http ://www.qnx.com – RTLinux http ://www.fmslab.com (IP acquise par VxWorks) – VxWorks http ://www.windriver.com RTOS libres – eCos http ://ecos.sourceware.org – RTAI http ://www.rtai.org – uclinux http ://www.uclinux.org – XENOMAI http ://www.xenomai.org 3 Quelques ordres de grandeur temporelle (source : [1]) – Nanoseconde (ns) : 109 Hz – temps d’accès à une RAM (5-80 ns) – durée d’un tick d’horloge processeur Pentium : TSC – Microseconde (µs) : 106 Hz – changement de contexte d’un processus, INT matérielle – systèmes radars, bus de terrain, transmission radio – Milliseconde (ms) : 103 Hz – temps d’accès à un disque SCSI ou IDE (5-20ms) – durée d’échantillonnage du son, protocole télécom – Seconde (s) : 1Hz – temps de réponse des applications logicielles (compilation, accès BD) – Mois, Années : – système de navigation des sondes Voyager 2 Linux n’est pas temps réel 2.1 OS à usage général (GPOS) Le noyau Linux (Kernel) Linux – Linux est un UNIX-like performant (AIX, HP-UX, Solaris) – développé par Linus Torvald en 1991 – code source ouvert, licence GPL (GNU General Public Licence) – support pour un grand nombre de plateforme : i386,Alpha,PowerPC... – GPOS : optimise l’utilisation classique : efficacité avant temps de réponse minimal – noyau échantillonné à 1000Hz (v2.6) → résolution timers et ordonnanceur – conforme norme POSIX 1003.1b (RT extension) 4 Le noyau Linux (Kernel) Une couche entre logiciel applicatif et le matériel – 2 modes (contextes) d’exécution : utilisateur et noyau Applicatif Shell GCC MyApp Espace Utilisateur Appels Systèmes (POSIX) IPC Memory Management ... Ordonnanceur Espace Kernel Threads Noyaux IRQ handler Drivers IRQ HAL (Hardware abstraction layer, optionnelle) Matériel CPU Périphériques Espace utilisateur/noyau Espace Utilisateur – contexte d’exécution des applications classiques – MMU : protection mémoire des applications – accès aux services du noyau par des fonctions spécifiques : les appels systèmes (mkdir, open, setgid) – langages évolués : C, C++, ada, fortran.. Espace Noyau – contexte d’exécution OS (appel système, ISR) – accès direct au hardware (I/O, mémoire physique,..) – pas de protection mémoire pour les threads noyaux – des modules permettent d’inclure dynamiquement du code dans le noyau – API spécifique au noyau (C et ASM) chaque espace a un privilège d’exécution processeur différent (mode protégé) Espace utilisateur/noyau – les appels systèmes et l’API du noyau sont mutuellement exclusifs – un processus utilisateur passe temporairement du mode utilisateur au mode noyau via un appel système Processus utilisateur API utilisateur Espace Utilisateur Appel Systeme Espace Kernel Temps d’execution 5 API : write, open (file) Tâche Noyau Espace Utilisateur API noyau Appel function Espace Kernel Temps d’execution API : printk,enable irq,find pci device mais pas open 2.2 Préemption et latence La préemption Définition – capacité d’un OS à interrompre une tâche en faveur d’une autre tâche (de priorité supérieure) – la préemption est nécessaire pour satisfaire une politique d’ordonnancement et initier un changement de contexte – les processus s’exécutant dans l’espace utilisateur sont toujours préemptibles sous Linux ← OS multitâche et multi-utilisateur La préemption Illustration 1 : – tâches s’exécutant dans l’espace utilisateur – ordonnancement en Round-Robin de 2 tâches ayant pour quantum (temps d’exécution alloué) 2 ticks d’horloge système – lorsque le quantum expire, l’ordonnanceur est appelé et choisi la prochaine tâche Priorité Préemption par l’OS: tâche non finie mais quantum expiré Espace utilisateur Processus A Espace noyau Processus B Processus A Appel système (open file) Timer INT temps La préemption Illustration 2 : – préemption d’une tâche A par une tâche de plus haute priorité B réveillée par une interruption 6 – au retour d’un ISR, Linux appelle toujours l’ordonnanceur : si une tâche B existe de plus haute priorité que A, B est exécutée au lieu de poursuivre avec A – cas non-préemptif : B devrait attendre pour démarrer la fin du process A ou son blocage sur une I/O, une ressource. Priorité Préemption par l’OS: tâche A non finie mais B a une priorité > Processus B Espace utilisateur Processus A Processus A ordonnanceur Espace noyau ISR (réveil de B) INT Timer INT temps La préemption dans l’espace noyau Définition – un noyau préemptif est également capable d’interrompre une tâche (routine) du noyau en faveur d’une autre tâche – un noyau préemptif est réentrant : une tâche noyau peut être appelée alors qu’un autre tâche noyau s’exécute – routines et threads noyaux : appels systèmes, ordonnanceur, kswapd (thread de libération de pages mémoire),.. Avantage d’un noyau préemptif (pour le temps réel) – exécution d’une tâche n’est pas retardée par un autre tâche de priorité inférieure mais qui est en mode noyau (lors d’un appel système par ex.) → réduction de la latence entre l’instant où un processus est prêt et l’instant où il démarre (cf. illustration suivante) La préemption dans l’espace noyau Illustration : cas du noyau préemptif – réveil par INT d’une tâche de haute priorité pendant l’exécution d’un appel système (routine noyau) – noyau préemptif : tâche B de priorité supérieure démarre immédiatement → on ne doit pas attendre la fin d’une tâche noyau pour démarrer un nouvelle tâche de priorité plus élevée – l’appel système reprendra lorsque A sera de nouveau la tâche active Priorité Processus B Mode utilisateur Préemption du noyau: appel système non fini mais B ready et priorité > Processus A Mode noyau Appel Système INT ordonnanceur ISR 7 temps La préemption dans l’espace noyau Illustration : cas du noyau non-préemptif – réveil par INT d’une tâche de haute priorité pendant l’exécution d’un appel système (routine noyau) – noyau non-préemptif : la routine noyau ne peut être stoppée au milieu → on doit attendre la fin d’une tâche noyau pour démarrer un nouvelle tâche même si elle est prioritaire – l’appel à l’ordonnanceur est retardé jusqu’à la fin de la tâche A latence Priorité Process B réveillé Non−préemption du noyau B ready et priorité > mais appel système pas fini Espace utilisateur Processus A Espace noyau Appel Système Processus B ordonnanceur INT temps Limitation de Linux pour le temps réel un OS prévu pour un usage général – optimisation du débit de traitement des applications au détriment du temps de réponse – avoir trop de points de préemption (réordonnancement) ralentit l’OS : – perte de temps en réordonnancements inutiles ; – perte de temps en changements de contexte d’exécution (overhead system) un noyau initialement non-préemptif – design facilité par l’absence de préemption dans l’espace noyau : – une seule tâche noyau à la fois accède aux structures de données du noyau ; – pas de risques de concurrences (race conditions) sur ces structures – évolution vers un noyau préemptif : multitâche dans l’espace noyau → définition de sections critiques (non-préemptibles, non-interruptibles) protégées par spinlock pour éviter les concurrences Limitation de Linux pour le temps réel – Préemption limitée au sein du noyau – noyau linux 2.0→2.2 : aucune préemption noyau – version 2.4 : préemption noyau en dehors des sections critiques – les portions de code du noyau non-préemptibles et non-interruptibles (sections critiques) sont conséquentes et source sporadiques de latences importantes – Ordonnanceur O(1) équitable – assure que toutes les tâches progressent même celles de plus basse priorité – priorités dynamiques des tâches (non strict), pas de prévention des inversions de priorité – Gestion mémoire et périphériques non-déterministe – pagination, rend non déterministe les accès mémoires (swapping sur disque) – réordonnancement des I/O (déplacement optimisé des tête de lecture) 8 Latence globale du noyau Linux En réponse à une interruption – Latence = latence d’interruption + durée du gestionnaire (ISR) + latence d’ordonnancement + durée de l’ordonnanceur Tâche bloquée Tâche en execution Tâche prête Espace utilisateur temps Latence d’interruption Odonnanceur (Scheduler) Gestionnaire d’interruption Espace noyau Latence ordonnanceur Interruption (INT) Latence du kernel Linux Facteurs de latence d’interruption – interruption masquée par le kernel (section critiques : spinlock) – lignes d’interruptions partagées (tous les gestionnaires sont exécutés) – ISR masquant l’interruption qu’il traite – arrivé d’autres interruptions de priorités + élevées (comportement correct et souhaitable) Facteurs de latence d’ordonnancement – l’ordonnanceur est appelé à chaque retour d’ISR (parfait !) mais : – arrivé d’autres interruptions (liées à des tâches de priorités inférieures) – durée d’ordonnancement des tâches : – constant sous 2.6 (O(1)), proportionnel au nombre de tâches sous 2.4 (O(n)) – temps de changement de contexte (save/load registres) – encore, présence d’une autre tâche de priorité + élevée à démarrer (retarde la tâche considérée mais comportement correct et souhaitable) Motivation pour un Linux temps réel RTOS dédiés et commerciaux – Pour : performances (Vxorks, LynxOS) et fonctionnalités (débogage) – Contre : coûts importants, sources majoritairement fermés GPOS libre avec extension RT – Pour : Open sources, gratuit, nombreux drivers, support communautaire – Contre : ”You can put racing stripes on a bulldozer but it won’t go any faster” (RTLinux Manifesto) – OS à usage général (GPOS), design en partie contradictoire avec un RTOS ; → modifications importantes du noyau pour approcher les performances des RTOS commerciaux 9 3 Vers un Linux temps réel Solution pour rendre TR le noyau Linux 1/Modifier le noyau – rendre le noyau le plus préemptible possible (fine granularity) – réduire le nombre de sections critiques – appeler l’ordonnanceur + souvent mais judicieusement – intégration progressive des modifications dans le noyau 2.6 par des patches 2/Ajouter un micro noyau temps réel – concept du ”Dual Kernel” ou co-noyau – adosser un micro-noyau temps réel à Linux – tout en conservant les fonctionnalités Linux – implications : – virtualisation des interruptions – IPC de communication inter-domaines entre Linux et le micro-noyau 3.1 Evolution de la préemption du noyau Patch : CONFIG PREEMPT VOLUNTARY Points explicites de préemption – insertion de points de préemption (réordonnancement) dans les sections de code non-préemptible et de longue durée d’exécution – – – – connu sous le nom de ”Low-Latency Patches” développé par Ingo Molnar en 2001 intégration dans les nouveaux noyau 2.6 (CONFIG PREEMPT VOLUNTARY) inconvénients : travail manuel, insérer judicieusement les points de préemption Points explicites de préemption : Illustration – code non-préemptif void prune_dcache(int count) { spin_lock(&dcache_lock); for (;;) { /* do some work*/ } spin_unlock(&dcache_lock); } – code avec points de préemption void prune_dcache(int count) { DEFINE_RESCHED_COUNT; redo: spin_lock(&dcache_lock); for (;;) { if (TEST_RESCHED_COUNT(100)) { RESET_RESCHED_COUNT(); if (conditional_schedule_needed()) { spin_unlock(&dcache_lock); 10 unconditional_schedule(); goto redo; } } /* do some work */ } spin_unlock(&dcache_lock); } Patch : CONFIG PREEMPT Points implicites de préemption – pas de risque à changer de tâche si hors ISR et aucun spinlock bloqué – chaque fin d’ISR ou spinlock est une opportunité de réordonnancement Implémentation – introduction d’un compteur preempt count – l’entrée et la sortie d’un spinlock incr/décremente le compteur – incrémenté par preempt disable() et décrémenté par prempt enable() – en sortie de spinlock, si preempt count==0 alors preempt enable() appelle la fonction de réordonnancement – la sortie d’un ISR réalise le même test – intégré à partir des noyaux 2.5.4 (CONFIG PREEMPT) Patch : CONFIG PREEMPT RT Le patch Realtime Préemption – faire de Linux un kernel totalement préemptif – conception entièrement préemptible, modification importante du code – totalement déterministe vis-à-vis de l’ordonnancement, et la gestion des interruptions – mécanisme d’héritage de priorité – patch en développement maintenu par Ingo Molnar – latence : <100 µs mais jitter de 300µs – objectif : Intégration dans le noyau officiel (CONFIG PREEMPT RT) Préemption du noyau linux Evolution quantitative 11 Linux 2.0 Linux 2.2−2.4 Premptible Linux 2.4−2.6 Real−time Linux 2.6 (in progress) Code Préemptible 3.2 Code Non−préemptible Approche dual-kernel (co-noyau) Linux + co-noyau Le concept – un micro-noyau temps réel est inséré entre le hardware et Linux – ordonnanceur temps réel spécifique – pas de dépendance aux sections critiques Linux – le micro-kernel capture en priorité les interruptions pour ses routines temps réel, avant Linux qui reçoit alors des interruptions virtuelles (Virtualisation des interruptions) – Linux est un OS de priorité secondaire (actif qd le co-noyau inactif) – le micro-noyau garantit des temps de commutation de contexte très courts → performant (latence < 20µs) – on bénéficie de tout l’environnement Linux (Xwindows, réseau) qui peut communiquer avec le micro-noyau via des IPC spécifiques Linux + co-noyau : historique Deux implémentations de la virtualisation – RTHAL : Realtime Hardware Abstraction Layer – interception et substitution des fonctions Linux gérant les interruptions matérielles au profit du micro-noyau temps réel ; – utilisé par RTLinux (propriétaire) et RTAI (libre) ; – approche brevetée par FSMLAB, rachat par VxWorks en 2007 – ADEOS : Adaptive Domain Environment for Operating Systems – permet le partage de ressources matérielles par plusieurs systèmes d’exploitation concurrents ; – développement conjoint avec Xenomai par Philip Gerum sur un travail théorique proposé par Karim Yaghmour en 2001 ; – migration de RTAI en 2003 sous ADEOS (à cause du brevet logiciel) 12 Linux temps réel : Bilan Type Archi. API Linux preempt Linux RT PREEMPT RTAI préemption native préemption native co-noyau Toutes i386,ppc,arm, mips,x86 64 i386,arm Xenomai co-noyau intégré i386,arm, ia64, ppc32/64 Posix, noyau Posix, noyau spécifique user/noyau multiple, user/noyau Latence moyenne 1-10ms Latence maximale ∞ 10-20 µs 70-400 ?µs < 5µs < 20µs < 5µs < 20µs Etat stable en devlpt. actif stable, dvlpt chaotique stable, dvlpt actif 4 Xenomai 4.1 ADEOS : virtualisation (co-noyau) ADEOS Un couche de virtualisation – disponible sous forme d’un patch pour Linux – permet la cohabitation de plusieurs domaines (OS complexe, nano-noyau,...) – tous ces domaines voient la couche Adeos et sont en concurrence pour traiter des événements externes (INT) ou internes (appel système) ADEOS notifie sur demande à chaque domaine : – les INT matérielles – appels systèmes des applications Linux – évènements déclenchés par le kernel (changement de tâche, signaux,..) ADEOS Le pipe d’évènement ou ”I-pipe” – chaque domaine à une priorité statique pour capturer les INT – évènements dispatchés par priorité aux domaines à travers un tube virtuel – root domain : le domaine nécessaire à l’installation des autres domaines (via des modules kernels ou adjonction de code) ADEOS Le pipe d’évènement et le log des INT – chaque domaine peut être ’gelé’ : les nouvelles interruptions ne lui sont pas distribuées ainsi qu’aux domaines de priorité inférieure 13 – INT sont cependant toujours reçues par les domaines de priorité supérieure et accumulées dans un log – exemple : Si Linux masque les INT pendant une section critique, un RTOS de priorité supérieur continue à les recevoir sans délais Xenomai Xenomai : un micro-noyau dans le domaine primaire ADEOS – réception prioritaire des INT, indépendamment des tentatives de masquage par les ISR et sections critiques de Linux – présence de 2 domaines entre lesquels une tâche temps réelle xenomai peut migrer : primaire (Xenomai) et secondaire (Linux) – gestion des priorités d’ordonnancement de ses tâches, indépendamment du domaine d’exécution → latence d’INT predictible Xenomai – Xenomai est un noyau temps réel permettant de programmer – des tâches temps réel entièrement dans l’espace noyau xenomai ; – des tâches temps réel (TR) dans l’espace utilisateur Tâche TR dans l’espace noyau Xenomai – programmation particulière sous forme d’un module noyau – héritage des premiers RTOS à co-noyau – utile pour développer des drivers temps réel – à déconseiller : pas de protection mémoire, d’utilitaires de débogage Tâche TR dans l’espace utilisateur – tâche exécutable à la fois dans le domaine primaire ADEOS (micro-noyau) ou le domaine secondaire (Linux) tout en étant ordonnancée par Xenomai – programmation sous forme d’une application classique – utilisation d’une bibliothèque pour l’API Xenomai 14 Xenomai Tâche TR dans l’espace utilisateur Domaine Linux (noyau standard) ISR ordonnanceur Migration Applications TR espace utilisateur Domaine Xenomai (co−noyau) ISR ordonnanceur TR Virtualisation d’interruptions Application TR espace kernel Contrôle masque IRQ Sources d’interruptions Xenomai Tâche TR dans l’espace utilisateur (détails) – protection mémoire pour la tâche – exécutée dans le domaine Xenomai (primaire) – gérée par l’ordonnanceur TR de xenomai ; – aucune inférence du noyau Linux, tâche toujours prioritaire sur une tâche Linux non-TR ; – latence minimaliste (lié au hardware) ; – si la tâche fait un appel système Linux : → tâche migrée dans le domaine Linux (secondaire) – exécutée dans le domaine Linux (secondaire) – le noyau Linux hérite la priorité de la tâche TR ; – la tâche TR reste ainsi en compétition avec les tâches du domaine Xenomai ; – tâche TR a accès aux appels systèmes Linux ; – latence supérieure (compétition possible avec tâches interne à Linux) ; – si la tâche fait un appel API Xenomai : → tâche migrée dans le domaine Xenomai (primaire) Xenomai Tâche TR dans l’espace utilisateur – illustration de la migration entre domaines 15 Appel système Linux domaine Linux domaine Xenomai temps Appel API Xenomai Migration Execution de la tâche Xenomai Bouclier d’interruption (optionel) Xenomai Besoins pour un bon support TR dans le domaine linux – granularité fine du noyau linux (préemption du noyau) – démarrage rapide d’une tâche RT prête dans le domaine secondaire ; – migration rapide du domaine Xenomai vers Linux – Prédictabilité de l’exécution (désactivé par défaut) – bouclier d’interruption permet de bloquer les INT vers le domaine Linux ; – l’exécution de la tâche TR dans le second domaine n’est pas perturbée par des ISR Linux – Gestion des inversion de priorité – gérée par héritage de priorité dans le premier domaine ; – à venir avec le patch PREEMPT RT pour le domaine secondaire (pas natif sous Linux) 4.2 Programmation temps réel avec Xenomai Xenomai API Caractéristiques – le noyau Xenomai fournit les services d’un RTOS générique – l’API native est une API parmi d’autres utilisant ces services – skins disponibles (POSIX, VxWorks,..) en plus de l’API Native – syntaxe commune pour la programmation dans l’espace noyau et utilisateur 16 Xenomai API Catégories de services – Gestion des tâches rt task create() : créer une tâche avec une priorité en paramètre rt task start() : démarrer une tâche rt task set periodic() : définir une tâche comme périodique – Gestion du temps et alarmes rt timer start() : initialiser des services de temporisation – synchronisation rt sem create() : créer un sémaphore – communication rt heap create( ,H SHARE) : créer un espace mémoire partagé – gestion d’I/O rt intr create( ) : créer un gestionnaire d’interruption Programmation avec l’interface Native – On se limite à l’étude de l’API native de Xenomai – Les autres API (skins) fournissent les mêmes services avec une syntaxe différente – On présentera la programmation dans l’espace noyau (module) et utilisateur (programmation classique) – En l’absence de programmation au niveau d’un driver, on privilégiera la programmation dans l’espace utilisateur (programmation plus classique, usage C++ possible, protection mémoire) Programmation dans l’espace Noyau Caractéristiques – les tâches se programment comme des modules noyaux – exécutées dans le domaine primaire : noyau Xenomai → pas d’appels systèmes – utilitaires pour les modules : – lsmod : liste des modules présent dans le noyau (kernel) – insmod : insérer le module dans le noyau – rmmod : retirer le module du noyau – programmation au plus prés du hardware (ring 0) mais risques associés – compilation avec l’utilitaire make, le compilateur gcc et un makefile adapté (v2.6). Programmation dans l’espace Noyau Makefile – makefile similaire à la compilation de module sous linux 2.6 – nécessite la présence des sources du noyau Linux sur la machine – exemple de Makefile : compilation du module exemple.c obj-m = exemple.o KDIR = /lib/modules/$(shell uname -r)/build PWD = $(shell pwd) EXTRA_CFLAGS = -I/usr/xenomai/include -I/usr/include/ default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -f *.o *.ko *.mod.c 17 Programmation dans l’espace Noyau – Exemple d’une tâche périodique #include <native/task.h> #include <native/timer.h> #define RTITI_TASK_PRIO #define RTITI_TASK_MODE #define RTITI_TASK_STKSZ 99 /*priorité la plus élevée*/ T_FPU|T_CPU(0) /*CPU 1 si plusieurs*/ 0 /*default size*/ RT_TASK myTask; /*descripteur de tâche*/ void mineTask (void* cookie) { rt_task_set_periodic(NULL, TM_NOW, SAMPLING_PERIOD); while(1) { ... } } int init_module (void) { rt_timer_set_mode( TM_ONESHOT ); /*initialisation du timer ns*/ rt_task_create( &mytask, "rtiti_task",TASK_STKSZ,TASK_PRIO,TASK_MODE ); /*creation*/ return 0; } void cleanup_module (void) { rt_task_delete( &myTask ); /*destruction de la tâche*/ } MODULE_LICENSE("GPL"); Structure de programmation d’un module noyau – il contient obligatoirement 2 fonctions : – init module () : fonction appelée lors de l’insertion du module dans le noyau (initialisation variables, structures, tâches et objets temps réel) ; – cleanup module () : fonction appelée lors du déchargement du module (libération des divers objets créés) Programmation dans le contexte utilisateur – les tâches TR Xenomai se programment comme des threads dans un programme utilisateur classique – on dispose des mêmes avantages que les programmes classiques : utilitaires de débogage, protection mémoire – accès transparent aux services Linux par migration du domaine primaire au domaine secondaire si nécessaire (appels fonctions Posix, usage de lib C : stdio.h) – exemple de makefile : compilation du source exemple.c APPLICATIONS = exemple XENO ?= /usr/xenomai XENOCONFIG=$(shell PATH=$(XENO):$(XENO)/bin:$(PATH) which xeno-config 2>/dev/null) CC=$(shell $(XENOCONFIG) --cc) CFLAGS=$(shell $(XENOCONFIG) --xeno-cflags) $(MY_CFLAGS) LDFLAGS=$(shell $(XENOCONFIG) --xeno-ldflags) $(MY_LDFLAGS) -lnative 18 all:: $(APPLICATIONS) clean:: $(RM) $(APPLICATIONS) *.o Exemple Xenomai : tâche périodique RT_TASK task_desc; int main (int argc, char *argv[]) { int err; /* Disable paging for this program’s memory. */ mlockall(MCL_CURRENT|MCL_FUTURE); /* Start the oneshot timer. */ err = rt_timer_start(TM_ONESHOT); if (err) fail(); /* Create a real-time task */ err = rt_task_create(&task_desc, "MyTaskName", TASK_STKSZ, TASK_PRIO, TASK_MODE); if (!err) /* If successfully created, start the task. */ rt_task_start(&task_desc,&sampling_task,NULL); ... } void sampling_task (void *cookie) { int err; /* The task will undergo a 100 usc periodic timeline. */ err = rt_task_set_periodic(NULL,TM_NOW,TASK_PERIOD); ... for (;;) { err = rt_task_wait_period(); if (err) break; /* Work for the current period */ } } 5 Annexe : aperçu de l’API Native Gestion des tâches et timers – Référence : Documentation de l’API inclue avec le code source Xenomai – Gestion des tâches rt rt rt rt rt rt rt task task task task task task task create(RT TASK* task, const char* name, ...) start(RT TASK* task, void(*)(void *cookie) entry, void* cookie) delete(RT TASK* task) join(RT TASK* task) suspend(RT TASK* task) resume(RT TASK* task) set periodic (RT TASK *task, RTIME idate, RTIME period) rt task wait period () rt task set priority (RT TASK *task, int prio) rt task catch(void(*)(rt sigset t) handler) ... 19 Création d’une nouvelle tâche Démarre la tâche TR ’entry’ Destruction de la tâche Attente fin de la tâche Mise en attente de la tâche Reprendre la tâche Rendre la tâche périodique (à utiliser avec wait period) Attente de la la prochaine période Modifie la priorité de la tâche Installe un gestionnaire de signal ... – API temps rt timer set mode (RTIME nstick) rt timer tsc (void) rt timer spin (RTIME ns) rt timer ns2tsc (SRTIME ns) Démarre le timer. Argument TM ONE SHOT pour un timer aperiodique et une valeur en ns pour un timer périodique. Retourne la valeur courante du TSC Attente active (charge le CPU) Conversion ns vers nombre de ticks CPU API services d’interruption – – – – association d’une routine de gestion (ISR) avec une INT l’ISR doit être une fonction courte, non-bloquante l’ISR peut lancer une tâche différée interruption masquée à l’entrée de l’ISR et démasquée en sortie rt intr create (RT INTR *intr, const char *name, unsigned irq, rt isr t isr, rt iack t iack, int mode) rt intr create (RT INTR *intr, const char *name, unsigned irq, int mode) rt intr delete (RT INTR *intr) rt intr wait (RT INTR *intr, RTIME timeout) rt intr enable (RT INTR *intr) rt intr disable (RT INTR *intr) Crée un descripteur d’INT associé à l’ISR ’isr’ dans l’espace kernel Création d’un descripteur d’INT dans l’espace user pour utilisation avec rt intr wait Destruction du descripteur d’INT Suspendre la tâche jusqu’à la prochaine INT Démasquer l’interruption Masquer l’interruption IPC : FIFO (boı̂te aux lettres (mailbox)) FIFO , communication asynchrone – une file de taille généralement bornée – le message a une taille et une structure prédéfinie – la lecture peut être bloquante ou non A rt rt rt rt pipe pipe pipe pipe B create (RT PIPE *pipe, const char *name, int minor, size t poolsize) delete (RT PIPE *pipe) read (RT PIPE *pipe, void *buf, size t size, RTIME timeout) write (RT PIPE *pipe, const void *buf, size t size, int mode) Création d’une fifo Destruction de la fifo Lire un message dans la fifo Ecrire un message dans la fifo IPC : Memoire partagée et allocation Les allocations mémoires en temps-réel – les processus d’allocations de mémoire par appel système (malloc) sont très coûteux en temps – la meilleur stratégie en TR : statique au début du programme – si il est nécessaire d’optimiser l’usage de la mémoire et d’avoir des allocations dynamiques : – mécanisme de tas mémoire (memory heap) de taille fixe – allocation possible de bloc dans ce tas – méthode garantissant un déterminisme temporel – le tas mémoire peut-être associé à un processus ou partagé 20 rt heap create (RT HEAP *heap, const char *name, size t heapsize, int mode) rt heap delete (RT HEAP *heap) rt heap alloc (RT HEAP *heap, size t size, RTIME timeout, void **blockp) rt heap free (RT HEAP *heap, void *block) Création d’un tas mémoire ou mémoire partagée Destruction d’un tas mémoire Allocation d’un bloc dans le tas Libération d’un bloc IPC : Synchronisation de tâches les Sémaphores (et Mutex) – résoudre le problème de l’utilisation de ressources communes – le sémaphore permet à plusieurs (contrairement au mutex) tâches de rentrer simultanément dans une section critique – assimilable à un compteur de ressources libres – le mutex implémente l’algorithme d’héritage de priorité rt sem create (RT SEM *sem, const char *name, unsigned long icount, int mode) rt sem delete (RT SEM *sem) rt sem p (RT SEM *sem, RTIME timeout) int rt sem v (RT SEM *sem) IPC : Autres services Autres services disponibles – drapeaux d’événement (Events Flag) – alarmes 21 Création d’un sémaphore Destruction d’un sémaphore Réservation d’une ressource du sémaphore Libération d’une ressource du sémaphore