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