Premiers pas avec Xenomai

Image non disponible


précédentsommairesuivant

VII. Premiers pas

VII-A. Un grand classique : « Hello world! »

Dans l'exemple ci-dessous, nous allons créer une tâche Xenomai qui affiche un message. Cela n'a aucun intérêt d'un point de vue temps réel me direz-vous. C'est vrai, mais cela permet tout de même de valider la chaîne de compilation et le support de Xenomai dans le noyau à travers un exemple basique.

Voici le code source que nous allons compiler :

 
Sélectionnez
#include <stdio.h>
#include <sys/mman.h>
#include <native/task.h>

static void task(void *arg)
{
  /* Here, we are in primary mode... */

  printf("Hello world!\n");

  /* Outch... printf accesses a Linux ressource so we are now
     in secondary mode */
}

int main (void)
{
  RT_TASK task_desc;
  
  /* disable memory swap */
  mlockall( MCL_CURRENT | MCL_FUTURE );
  
  if (rt_task_spawn( &task_desc,  /* task descriptor */
                     "my task",   /* name */
                      0           /* 0 = default stack size */,
              99          /* priority */,
              T_JOINABLE, /* needed to call rt_task_join after */
              &task,      /* entry point (function pointer) */
              NULL        /* function argument */ )!=0)
  {
    printf("rt_task_spawn error\n");
    return 1;
  }

  /* wait for task function termination */
  rt_task_join(&task_desc);
  
  return 0;
}

Le mécanisme de pagination abstrait l'adressage mémoire. Cela permet de disposer de plus de mémoire vive qu'en réalité, la différence virtuel/réel étant comblée par une mémoire plus lente (disque dur). Dans une application temps réel, il est inconcevable d'avoir une variation dans les temps d'accès mémoire, c'est pourquoi le swap doit impérativement être désactivé en appelant mlockall.

VII-B. La compilation

On va simplement chercher le répertoire contenant les en-têtes et la bibliothèque :

 
Sélectionnez
[dchabal@localhost tuto]$ gcc -I/usr/xenomai/include hello.c -L/usr/xenomai/lib -lnative -o hello

Par la suite nous verrons une méthode de compilation plus portable.

VII-C. L'exécution

 
Sélectionnez
[dchabal@localhost tuto]$ ./hello
./hello: error while loading shared libraries: libnative.so.1: cannot open shared object file: No such file or directory
[dchabal@localhost tuto]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/xenomai/lib
[dchabal@localhost tuto]$ ./hello
Xenomai: binding failed: Operation not permitted.
[dchabal@localhost tuto]$

Qu'est-ce qui ne va pas ici ?

La première erreur vient du fait que la bibliothèque libnative.so.1 est chargée dynamiquement et que son chemin ne se trouve pas dans la variable d'environnement LD_LIBRARY_PATH.

On peut également ne pas toucher au LD_LIBRARY_PATH et modifier le fichier /etc/ld.so.conf puis lancer ldconfig (en tant que root), comme ceci:

 
Sélectionnez
[root@localhost tuto]# more /etc/ld.so.conf
include ld.so.conf.d/*.conf
/usr/X11R6/lib
/usr/lib/qt3/lib64
/usr/xenomai/lib
[root@localhost tuto]# ldconfig
[root@localhost tuto]#

La seconde erreur est qu'il faut avoir les droits root pour lancer les applications Xenomai, d'où le message d'opération non autorisée.

En tant que root, on a bien le résultat escompté :

 
Sélectionnez
[root@localhost tuto]# ./hello
Hello world!
[root@localhost tuto]#

Le temps d'accès à la mémoire doit être constant. Or, ce n'est pas garanti lorsque le swap disque est activé.
Il faut donc impérativement le désactiver avec la fonction mlockall.
L'inconvénient est que l'application aura moins de ressources mémoire.
Il faudra être particulièrement vigilant lors de l'appel aux fonctions de type malloc (secondary mode) en contrôlant le code de retour.

VII-D. Que se passe-t-il ?

Les commandes top, fuser... existaient sous Linux afin de surveiller l'état du système, comment fait-on maintenant pour surveiller nos nouvelles tâches ?

Les variables internes de Xenomai sont accessibles dans le répertoire /proc/xenomai(34). L'arborescence est alors la suivante :

affinity

CPU utilisés pour les tâches Xenomai. Exemple: 00000003, soit en binaire 0000.0011 pour le dernier octet, correspondant aux CPU0 et CPU1 sur un Intel Dual Core ;

apc

L'APC est le mécanisme qui optimise de la prise en compte des handlers d'interruption Linux en attente lorsque Linux reprend la main ;

faults

Liste les erreurs levées par processeur ;

hal

Version d'Adeos ;

heap

Size of the private stack pool (comme son nom ne l'indique pas) internes configurés dans Size of the system heap et Size of the private stack pool.

interfaces/

Nombre d'applications Xenomai en cours d'exécution, classées par skins ;

native ;

rtdm ;

sys ;

irq

Comptage du nombre d'interruptions utilisées par Xenomai ;

latency

Latence du scheduler (expliqué dans Scheduling latency) ;

registry/

Liste des objets temps réel gérés par Xenomai ;

rtdm/

Informations concernant les drivers temps réel ;

fildes

Liste des descripteurs (attention contrairement à Linux, les descripteurs commencent à 0) ;

named_devices

Liste des périphériques, rtserx par exemple pour les « ports série temps réel ». Alter ego du /dev Linux ;

open_fildes

Liste des descripteurs pointant un périphérique utilisé ;

protocol_devices

Liste des protocoles utilisés par les périphériques (CAN) ;

rttest0/ ;

information

Informations (version, type de drivers...) disponibles pour chaque périphérique présent dans le répertoire RTDM. rttest0 correspond ici à un driver virtuel dédié au test ;

rttest1/ ;

information ;

rttest2/ ;

information ;

sched

Liste les tâches dans le scheduler Xenomai (voir ci-dessous) ;

stat

Statistiques (utilisation CPU...) collectées si l'option du noyau est activée ;

timebases

États des timers des différentes skins ;

timer

État du timer, exemple :

 
Sélectionnez
status=on+watchdog:setup=0:clock=379818707114:timerdev=lapic:clockdev=tsc

status : le timer est actif et le watchdog de débogage est activé ;
setup : latence du timer en nanosecondes ;
clock :nombre de ticks émis par clockdev écoulés depuis la mise sous tension du système ;
timerdev : timer utilisé (lapic) ;
clockdev : horloge utilisée (time stamp counter : timer haute résolution implémenté dans le CPU) ;

timestat/

Indications sur la programmation des timers ;

version

Version de Xenomai.

L'état d'ADEOS est également consultable dans le répertoire /proc/ipipe comme nous l'avons vu précédemment.

Nous avions dit qu'une tâche en secondary mode était dans le scheduler Linux, il est temps maintenant de le vérifier. En insérant un appel à pause() après notre printf(), nous retrouvons bien notre tâche via un ps :

 
Sélectionnez
[dchabal@localhost xenomai]$ ps -eTo pid,ppid,ucmd,class,rtprio,nice --sort class
  PID  PPID CMD             CLS RTPRIO  NI
    1     0 init            TS       -   0
...
 4059  3926 hello           TS       -   0
 4059  3926 my task         FF      99   -
[dchabal@localhost xenomai]$

Nous avons donc bien notre tâche Linux principale (code du main) qui s'appelle hello et qui est dans la classe SCHED_OTHER (TS pour time share), et notre tâche Xenomai en secondary mode "my task" qui a conservé sa priorité 99. Elle est bien dans la classe SCHED_FIFO (FF, on aurait eu RR pour SCHED_RR).

Et si maintenant on jette un œil du côté du scheduler Xenomai :

 
Sélectionnez
[dchabal@localhost xenomai]$ cat /proc/xenomai/sched
CPU  PID    PRI      PERIOD     TIMEOUT    TIMEBASE  STAT       NAME
  0  0       -1      0          0          master    R          ROOT/0
  1  0       -1      0          0          master    R          ROOT/1
  0  4059    99      0          0          master    X          my task
[dchabal@localhost xenomai]$

On retrouve encore notre tâche "my task", marquée d'un 'X', c'est-à-dire en secondary mode.

La tâche ROOT est Linux en mode idle (priorité symboliquement notée -1).

Le tableau ci-dessous(35) liste les statuts possibles :

Tableau 1: Statuts des tâches
S Forcibly suspended.
w/W Waiting for a resource, with or without timeout.
D Delayed (without any other wait condition).
R Runnable.
U Unstarted or dormant.
X Relaxed shadow.
H Held thread.
b Priority boost undergoing.
T Ptraced and stopped.
l Locks scheduler.
r Undergoes round-robin.
s Interrupt shield enabled.
t Mode switches trapped.
o Priority coupling off.
f FPU enabled (for kernel threads).

précédentsommairesuivant
Je rappelle à ceux qui ne sont pas familiers de Linux que tout n'est que répertoire et fichier dans cet OS.
Extrait de include/nucleus/thread.h.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+