• Aucun résultat trouvé

Les donn´ees partag´ees

5.2 Formalisation du mod`ele en TLA+

5.2.4 Les donn´ees partag´ees

Dans notre mod`ele, on utilise deux types de ressources partag´ees, des ressources prot´eg´ees et non prot´eg´ees. Les ressources prot´eg´ees le sont par un m´ecanisme explicite d’exclusion mutuelle, le protocole que l’on a choisi d’impl´ementer est IPCP(Immediate Priority Ceiling Protocol[RC04]). Ce protocole a principalement ´et´e choisi pour sa simplicit´e d’implantation : lorsqu’une tˆache acc`ede `a une ressource, elle change au plus une fois de prio-rit´e pour prendre la plus haute prioprio-rit´e. D`es qu’un thread entre dans une zone critique, il prend la plus haute priorit´e des threads pouvant acc´eder `a cette ressource. Les ressources non prot´eg´ees servent `a mod´eliser des ressources partag´ees dont l’int´egrit´e est cens´ee ˆetre garantie par l’ordonnancement des threads. On v´erifiera que ces donn´ees non prot´eg´ees ne sont jamais utilis´ees par deux threads au mˆeme instant.

On introduit ici de nouvelles constantes permettant de d´ecrire les res-sources et leurs propri´et´es :

– SharedData : l’ensemble des ressources partag´ees,

– Protected : l’ensemble des ressources partag´ees prot´eg´ees, – Unprotected : l’ensemble des ressources partag´ees non prot´eg´ees, – data Priority : la priorit´e d’une ressource (plus haute priorit´e des

threads pouvant acc´eder `a la ressource),

– accessing thread : fonction qui associe `a chaque donn´ee la liste des threads pouvant l’utiliser,

– access time : fonction qui associe `a un couple donn´ee, thread l’inter-valle pendant lequel le thread acc`ede `a la ressource.

On ajoute aussi de nouvelles variables au mod`ele :

– awaiting resource : l’ensemble des threads en attente d’une res-source,

– AccessedBy : une fonction qui associe `a chaque donn´ee le thread qui l’utilise,

– actual Priority : la priorit´e courante du thread.

Verrouiller et d´everrouiller une ressource

On commence par d´efinir deux op´erations permettant de modifier l’´etat d’une ressource partag´ee. La variable AccessedBy associe `a chaque ressource le nom du thread qui est en train de l’utiliser. On utilise la valeur sp´eciale bot thread dans le cas o`u la ressource est libre. La premi`ere op´eration, lock resourcemodifie cette variable, elle associe `a la ressource pass´ee en param`etre le thread en cours d’ex´ecution. La seconde, release resource, associe `a la ressource la valeur bot thread signifiant que la ressource est libre.

lock resource(sd ) =

∧ AccessedBy = [d ∈ SharedData 7→ if d = sd

then computing thread else AccessedBy[d ]] release resource(sd ) =

∧ AccessedBy = [d ∈ SharedData 7→ if d = sd

then bot thread else AccessedBy[d ]] Acc`es `a une ressource

On va de nouveau enrichir notre automate d’une nouvelle transition, la garde de cette transition devient vraie lorsque le thread en cours d’ex´ecution entre dans sa section critique. L’action associ´ee `a cette transition verrouille la ressource si elle est libre. Si la ressource est d´ej`a verrouill´ee et que la ressource est prot´eg´ee alors, le thread suspend son ex´ecution et passe dans un ´etat o`u il attend que la ressource redevienne libre. Dans le cas o`u la ressource n’est pas prot´eg´ee, on consid`ere que l’acc`es par deux threads en mˆeme temps `a une ressource est une erreur de conception, on va donc faire passer notre automate dans un ´etat puits. Lors de la phase de v´erification, si le syst`eme arrive dans cet ´etat, le model checker consid´erera qu’il a trouv´e un chemin menant `a un interblocage et affichera la trace correspondante.

5.2. FORMALISATION DU MOD `ELE EN TLA+ 87

– le thread en cours d’ex´ecution fait partie des threads pouvant acc´eder `

a la ressource pass´ee en param`etre , – ce thread entre dans sa section critique ,

– et que ce thread n’a pas d´ej`a verrouill´e cette ressource.

Dans l’op´eration associ´ee `a cette transition, on formalise les trois cas pr´esent´es plus haut :

– la ressource n’est pas prot´eg´ee, mais un autre thread y acc`ede, on bloque l’ex´ecution,

– si elle est prot´eg´ee et verrouill´ee le thread en cours d’ex´ecution passe dans un ´etat o`u il attend la ressource,

– sinon il la verrouille et prend sa priorit´e si celle-ci est sup´erieure `a la sienne.

Afin de rendre plus lisible la sp´ecification, on a d´efini trois op´erations, protected locked(sd), unprotected locked(sd) et block(mt). Les deux premi`eres permettent de tester si la donn´ee pass´ee en param`etre est ver-rouill´ee par un thread, la troisi`eme fait passer le thread en param`etre dans l’´etat en attente de ressource.

Les expressions block(mt), protected locked(sd), et unprotected locked(sd) ont ´et´e introduites pour segmenter le code et le rendre plus lisible.

must access(d ) =

∧ computing thread 6= bot thread ∧ d ∈ SharedData

∧ computing thread ∈ accessing thread [d ] ∧ access time[d , computing thread ][1]

= execution timer [computing thread ] ∧ AccessedBy[d ] 6= computing thread

access =

let sd = choose sd ∈ SharedData : must access(sd )in if unprotected locked(sd ) then

false

else if protected locked(sd ) then ∧ block (computing thread ) ∧ computing thread = bot thread else ∧ lock resource(sd )

∧ actual Priority = [t ∈ Lifted Thread 7→ if t = computing thread

∧ sd ∈ Protected

∧ data Priority[sd ] > actual Priority[t] then data Priority[sd ]

block(mt) =

∧ awaiting resource = awaiting resource ∪ {mt} ∧ ready = ready \ {mt}

protected locked(sd ) =

sd ∈ Protected ∧ AccessedBy[sd ] 6= bot thread unprotected locked(sd ) =

sd ∈ Unprotected ∧ AccessedBy[sd ] 6= bot thread

Lib´erer une ressource

On d´efinit de mani`ere tr`es similaire `a la transition pr´ec´edente une tran-sition pour la sortie de section critique. La garde indique simplement que la ressource est bien verrouill´ee par le thread en cours d’ex´ecution et que celui-ci arrive `a la fin de sa section critique.

Lorsque cette garde est vraie, on lib`ere la ressource (appel `a l’op´eration release resource) et la priorit´e du thread redescend soit `a la priorit´e du thread, soit `a la plus haute priorit´e des ressources qu’il verrouille encore.

must release(d ) = ∧ d ∈ SharedData

∧ computing thread 6= bot thread

∧ internal mode[computing thread ] ∈ accessing thread [d ] ∧ access time[d , computing thread ][2]

= execution timer [computing thread ] ∧ AccessedBy[d ] = computing thread

accessed data = {d ∈ SharedData :

AccessedBy[d ] = computing thread } max prio data =

choose d ∈ accessed data :

∀ od ∈ accessed data : data Priority[od ] ≤ data Priority[d ]

release =

let sd = choose sd ∈ SharedData : must release(sd )in ∧ release resource(sd )

∧ actual Priority = [t ∈ Lifted Thread 7→ if t = computing thread then

if accessed data6= {} then data Priority[max prio data] else Priority[t]

5.2. FORMALISATION DU MOD `ELE EN TLA+ 89

Sortir de l’´etat “ en attente de ressource ”

On ajoute enfin une derni`ere transition permettant aux threads en at-tente d’une ressource critique de retourner dans l’´etat ready d`es que la ressource se lib`ere.

La garde de cette op´eration est vraie si au moins un thread de l’ensemble awaiting resourcen’est plus bloqu´e par une resource partag´ee verrouill´ee. Dans ce cas, on calcule l’ensemble des threads `a lib´erer et cet ensemble de threads sort de l’´etat awaiting resource et revient dans l’´etat ready.

canUnblock = {x ∈ awaiting resource : ¬protected locked (x )} 6= {} unblock =

let free = {x ∈ awaiting resource : ¬protected locked (x )}in ∧ awaiting resource= awaiting resource \ free

∧ ready= ready ∪ free