• Aucun résultat trouvé

D´efinition d’un ordonnanceur simple

5.2 Formalisation du mod`ele en TLA+

5.2.2 D´efinition d’un ordonnanceur simple

On commence par introduire les notions permettant de d´efinir un ordon-nanceur basique. L’ensemble des threads du syst`eme est repr´esent´e par la constante (Thread) d´efinie dans le module architecture model. On consi-d`ere qu’un thread peut se trouver dans trois ´etats diff´erents, en attente d’activation (awaiting dispatch), prˆet (ready), et en cours d’ex´ecution (running). Pour repr´esenter ces trois ´etats, le module kernel contient trois variables permettant de repr´esenter l’´etat courant des threads du syst`eme : – awaiting dispatch est un sous ensemble de Thread contenant les

threads en attente d’activation ;

– ready un autre sous ensemble de thread, disjoint du premier, contient les threads prˆets ;

l’en-5.2. FORMALISATION DU MOD `ELE EN TLA+ 73

semble Thread, elle repr´esente le seul thread ´eventuellement en cours d’ex´ecution.

variables awaiting dispatch, ready, running TypeInvariant =

static type invariant

∧ awaiting dispatch ∈ subset Thread ∧ ready ∈ subset Thread

∧ computing thread ∈ Lifted Thread dynamic type invariant

∧ awaiting dispatch ∩ ready = {} ∧ awaiting dispatch ∪ ready = Thread ∧ computing thread ∈ ready ∪ {bot thread }

L’ensemble Lifted Thread correspond `a l’ensemble Thread auquel on a ajout´e la valeur bot thread, cette valeur est utilis´ee dans le cas o`u aucun thread n’est en cours d’ex´ecution, et repr´esente donc `a ce moment-l`a, la valeur de la variable computing thread. On d´ecrit ensuite les transitions entre ces ´etats : dispatch, resume, preempt, et complete. On s´epare toutes ces transitions en deux parties distinctes, la garde et les actions `a effectuer.

Activation d’un thread

Un thread est activ´e s’il est p´eriodique et qu’il arrive en d´ebut de p´e-riode ou s’il est ap´eriodique et qu’un de ses ports event pouvant d´eclencher l’activation contient un ´el´ement. Cette condition s’exprime en TLA de la mani`ere suivante :

can dispatch(th) =

∨ th ∈ Periodic ∧ period timer [th] = 0 ∨ th ∈ Aperiodic ∧ ∃ p ∈ In event port :

p ∈ dispatch ports[th] ∧ iep event cpt[p] > 0

Dans cette expression Aperiodic et Periodic sont deux ensembles constants formant une partition de l’ensemble Thread. In event port repr´esente l’en-semble des ports event du syst`eme. Enfin, dispatch ports est une fonction qui associe `a chaque thread ap´eriodique l’ensemble de ses ports pouvant d´eclencher son activation. Toutes ces constantes sont d´efinies dans le mo-dule architecture model et proviennent directement du mod`ele AADL. On trouve ensuite dans cette expression deux variables, iep event cpt[p] et period timer[th]. La premi`ere est une fonction qui associe `a chaque port event en entr´ee la valeur de son compteur d’´ev´enements. La seconde associe `a chaque thread p´eriodique une horloge qui compte le temps entre deux activations. Enfin, le param`etre th repr´esente un thread. Cette expres-sion retourne un bool´een lors de son ´evaluation, vrai si le thread th est prˆet `

Au moment de son activation, le thread quitte son ´etat d’attente et passe dans l’´etat prˆet, ses ports et ses horloges sont mis `a jours. Si le thread est p´eriodique, tous ses ports sont mis `a jour. Mais si le thread est ap´eriodique, seule une sous partie de ses ports est modifi´ee. L’ensemble des ports `a mo-difier d´epend de du port ayant d´eclench´e le dispatch. On met ensuite `a jour les diff´erentes horloges associ´ees au thread.

dispatch =

let th = choose th ∈ awaiting dispatch : can dispatch(th)in ∧ awaiting dispatch = awaiting dispatch \ {th}

∧ ready = ready ∪ {th}

∧ deadline timer = [x ∈ Thread 7→

if x = th then Deadline[th] else deadline timer [x ]] ∧ execution timer= [x ∈ Thread 7→

if x = th then 0 else execution timer [x ]] ∧ period timer = [x ∈ Periodic 7→

if x = th then Period [th] else period timer [x ]]

L’expression TLA LET ... IN nous permet de choisir un ´el´ement satis-faisant un pr´edicat dans un ensemble. Les expressions set port dispatch periodic(th) et set port dispatch aperiodic(th,ep) sont des actions servant `a mettre `a jour les ports. Les variables repr´esentant les horloges (deadline timer, execution timer, period timer) sont des fonctions qui associent une valeur d’horloge `a chaque thread. Au moment de l’activation d’un thread, on veut r´einitialiser seulement la valeur associ´ee `a ce thread. On d´ecrit alors la nouvelle fonction comme ´etant modifi´ee pour le thread consi-d´er´e et identique pour toutes les autres valeurs du domaine de la fonction. On peut apparenter cette mise `a jour `a l’utilisation de l’op´erateur de sur-charge d’une fonction en B. On montre plus tard dans cette partie comment ´evoluent ces horloges.

La description de cette action n’est pas compl`ete, mais elle est suffisante pour la pr´esentation du m´ecanisme d’ordonnancement. On compl´etera cette description par la suite 5.2.

Gestion de l’ordonnancement

Dans un premier temps, on doit ˆetre capable d’´elire le thread prˆet de plus haute priorit´e. L’expression TLA suivante est vraie si le thread pass´e en pa-ram`etre a une priorit´e sup´erieure `a tous les autres threads prˆets. On introduit ici une nouvelle constante du module architecture model, Priority est une fonction qui associe `a chaque thread sa priorit´e.

maxPrio(th) =

5.2. FORMALISATION DU MOD `ELE EN TLA+ 75

On doit commencer l’ex´ecution d’un nouveau thread si le thread en cours d’ex´ecution n’a plus la priorit´e maximum. Cette condition est traduite par la condition suivante.

canResume =

∧ ¬maxPrio(computing thread )

Si cette condition est vraie on doit ´elire et commencer `a ex´ecuter le nouveau thread de plus haute priorit´e. Lorsqu’un thread commence son ex´e-cution, il ne quitte pas l’ensemble des threads actifs. La variable computing thread peut avoir une valeur particuli`ere appel´ee bot thread, cette valeur est utilis´ee lorsqu’aucun thread n’est actif. On associe `a cette valeur une priorit´e minimale. Une pr´econdition de cette op´eration est que l’ensemble readyest non vide.

resume =

let mt = choose mt ∈ ready : maxPrio(mt)in ∧ computing thread = mt

La compl´etion

On consid`ere dans notre mod`ele qu’un thread a toujours le mˆeme temps d’ex´ecution. Dans la litt´erature, le temps d’ex´ecution d’une tˆache est sou-vent donn´e comme un intervalle entre un meilleur temps d’ex´ecution et un pire temps d’ex´ecution. Cette approche est difficile `a utiliser lorsqu’on en-visage d’´etudier la validit´e de propri´et´es par model checking. L’utilisation d’intervalles fait exploser le nombre d’´etats g´en´er´es par le model checker. De plus, dans la plupart des cas, on est int´eress´e par le pire cas d’ex´ecution. On verra par la suite que l’on peut l´eg`erement relˆacher cette contrainte en utilisant la notion de mode interne aux threads. Un thread termine donc son ex´ecution lorsque l’horloge qui compte son temps d’ex´ecution atteint la valeur de son temps d’ex´ecution total. La constante Execution time ap-partient au module architecture model, et associe un temps d’ex´ecution `

a chaque thread. hasComplete =

∧ computing thread 6= bot thread il y a bien un thread courant ∧ execution timer [computing thread ]

= Execution time[computing thread ]

On effectue tr`es peu d’actions au moment de la compl´etion : le thread en cours d’ex´ecution quitte l’´etat prˆet et revient dans l’´etat en attente d’activa-tion. Le processeur est lib´er´e, il n’y a plus de threads en cours d’ex´ecud’activa-tion. Et enfin, on envoie ´eventuellement des donn´ees ou des ´ev´enements par les ports.

complete =

∧ awaiting dispatch = awaiting dispatch ∪ {computing thread } ∧ ready = ready \ {computing thread}

∧ computing thread = bot thread

La gestion de l’´ecoulement du temps

Afin de mod´eliser l’´ecoulement du temps en TLA, on attache trois hor-loges `a chaque thread, une associ´e `a la p´eriode du thread, la seconde `a son temps d’ex´ecution et la troisi`eme `a son ´ech´eance, et on d´efinit une op´eration, tick. Le mod`ele d’´ecoulement du temps adopt´e est celui o`u on distingue des op´erations discr`etes o`u seul l’espace d’´etat ´evolue et une op´eration de d´e-lai o`u seul le temps ´evolue. Les horloges associ´ees aux threads ont d´ej`a ´et´e pr´esent´ees dans 2.2.2. Elles sont initialis´ees au moment de l’activation du thread. L’op´eration tick incr´emente une variable now, g´en´eralement dite de temps absolu, cette variable est initialis´ee `a z´ero et augmente continuelle-ment. Elle n’est ni modifi´ee ni acc´ed´ee dans le mod`ele, elle ne fait pas partie des variables prises en compte pour le model checking. Cette variable est utile lorsqu’on doit lire le r´esultat de l’analyse du model checker. Elle per-met de mieux suivre la chronologie des divers ´etats. On utilise ici la m´ethode propos´ee par L.Lamport dans [Lam05].

Tick =

∧ now = now + 1

∧ deadline timer = [t ∈ Thread 7→ if ∨ t ∈ ready

∨ (t ∈ awaiting dispatch ∧ deadline timer [t] > 0) then deadline timer[t] − 1

else deadline timer[t]]

∧ execution timer= [t ∈ Thread 7→ if t = computing thread then execution timer[t] + 1

else execution timer[t]]

∧ period timer = [t ∈ Periodic 7→ period timer[t] − 1]

Dans le but de r´eduire le nombre d’´etats g´en´er´es par le model checker on pourrait calculer dans cette op´eration l’instant du prochain ´ev´enement `

a prendre en compte, et faire avancer directement le mod`ele jusqu’`a cet instant.

Automate g´en´eral de l’ordonnanceur

On pr´esente ici l’op´eration Next qui d´ecrit la transition globale du sys-t`eme. Dans cette expression, si une des conditions pr´esent´ees est vraie on

5.2. FORMALISATION DU MOD `ELE EN TLA+ 77 awaiting dispatch active running resume preempt dispatch complete

Fig. 5.5 – Automate de gestion simplifi´e des threads

ex´ecute l’op´eration correspondante. L’ordre dans lequel on ´evalue les ex-pressions est important. Un thread qui se termine peut devoir envoyer des donn´ees `a un thread qui doit ˆetre activ´e. De la mˆeme mani`ere, avant d’´elire le thread de plus haute priorit´e, on veille `a avoir activ´e tous les threads qui pouvaient l’ˆetre. Enfin, on fait avancer le temps seulement si aucune autre action n’est possible. On peut repr´esent´e le code TLA suivant par la figure 5.5.

Next =

if hasComplete then complete

else if ∃ th ∈ awaiting dispatch : can dispatch(th) then dispatch

else if canResume then resume

else Tick