• Aucun résultat trouvé

Fiabiliser l'exécution des tâches critiques

Les tâches hébergées par un même processus logique ne sont pas exécutées de manière isolée. D'un point de vue pratique, si l'exécution d'une tâche provoque une erreur grave, c'est l'ensemble des tâches hébergées qui est touché car le processus logique dans son ensemble risque d'être interrompu.

Pour contourner cette difficulté, une solution consiste à isoler les tâches dont le fonctionnement n'est pas éprouvé dans des processus logiques séparés. Si une telle tâche vient à provoquer une erreur sérieuse, le processus qui l'héberge sera bel et bien détruit mais il n'affectera pas les autres tâches de l'application.

Parallèlement, on peut mettre en place facilement une surveillance du fonctionnement d'un processus logique et identifier ses arrêts de fonctionnement pour relancer les éléments défaillants. La surveillance est réalisée en plaçant une tâche à déclenchement périodique dans le processus logique à surveiller. Cette

76 - Chapitre 3

tâche génère à chaque exécution un évènement sur un signal spécifique appelé signal de battement. Une seconde tâche, placée dans un processus logique différent, est chargée de surveiller ce signal de battement. Elle prendra en charge la reconstruction de l'application si aucun évènement ne se produit sur le signal pendant une durée supérieure à la périodicité de la tâche surveillée. Un nouveau processus logique sera créé dans lequel les composants détruits seront ré- instanciés.

Cette stratégie d'isolement conduit à multiplier les processus logiques. Or, ces derniers sont plus lourds à gérer que de simples tâches. Cette méthode ne peut donc être employée qu'avec parcimonie.

C'est pourquoi NJN propose une autre stratégie basée sur la gestion d'exceptions par sauts longs (setjump et longjump). Il n'est plus nécessaire d'isoler les tâches dangereuses dans des processus spécifiques. Cependant, cette technique ne prémunit pas de toutes les défaillances d'exécution. Pour conserver en toutes circonstances une structure de données cohérente, NJN procède à l'exécution en deux temps.

La première phase commence par une sauvegarde de l'état de la pile du système1.

Le corps de la tâche est ensuite exécuté. Cette phase est la plus critique car les erreurs d'exécution qui peuvent apparaitre à cet instant découlent principalement du code de l'application, c'est-à-dire d'une erreur de conception d'un composant ou d'une utilisation non-conforme de celui-ci. Aucune modification de la structure de donnée d'NJN n'est opérée pendant cette phase ce qui préserve son intégrité. NJN se contente de lister les opérations appelées par la tâche. Si une erreur grave se produit pendant cette phase, l'état de la pile du système est restitué2 et la liste des

opérations est détruite. L'échec d'exécution est signalé et NJN passe à l'exécution de la tâche suivante.

La seconde phase est engagée si l'exécution s'est passée sans encombre. Toutes les opérations listées sont effectivement opérées sur la structure de données d'NJN. Les erreurs qui peuvent se produire pendant cette seconde phase sont plus rares car elles découlent plus vraisemblablement d'un bogue dans le code d'NJN que d'une erreur de l'application. Par ailleurs, chaque opération peut être effectuée sous un contrôle beaucoup plus étroit que pendant la première phase.

* * *

Les propriétés dynamiques d'NJN ont conduit à une définition du temps en trois dimensions. La première correspond à la représentation commune du temps. Les deux suivantes, les cycles Δ et δ, assurent la préservation des relations causales entre les données pendant les phases de relaxation du système. Les cycles Δ sont relatifs à l'exécution des tâches tandis que les δ permettent la propagation des données à travers le réseau de signaux. Cette représentation du temps permet d'établir les relations temporelles entre les différents évènements de l'application.

1 Concrètement, il s'agit d'un appel à setjump. 2 Par un appel à longjump.

Le protocole de synchronisation - 77 Trois types d'évènements sont définis : les évènements d'écriture et de lecture qui représentent les opérations de même nom effectuées par les tâches sur les signaux et les évènements d'exécution qui représentent l'exécution d'une tâche. Ces évènements sont liés par une structure de données, appelée graphe causal, qui matérialise leurs relations de cause à effet. Ce graphe, construit au fur et à mesure de l'exécution, conserve la trace de toutes les opérations effectuées par l'application. En cas de nécessité, il permet de réaliser les retours arrière.

Nous avons à présent terminé la construction du modèle d'exécution d'NJN. Bien qu'étant évènementiel, notre modèle produit des applications dont le comportement peut être parfaitement déterministe. Le principe d'ordonnancement qu'il met en œuvre tranche radicalement avec les techniques évènementielles traditionnelles. Il s'inspire des techniques de simulation distribuées qui traitent nativement les relations causales entre les évènements du système. C'est cette particularité qui confère à notre modèle ses propriétés déterministes. Deux types de protocoles sont classiquement employés dans les simulateurs : les premiers sont dits conservatifs, les seconds optimistes. Ces derniers donnent aux processus logiques de l'application une grande souplesse d'exécution. Les situations de violation de causalité sont détectés à postériori. Lorsque cela est nécessaire, un mécanisme de retour arrière est mis en œuvre pour retrouver une état du système cohérent. Le protocole de synchronisation utilisé par NJN est de ce type et lui permet de s'adapter aux modifications structurelles opérées sur le système pendant l'exécution sans qu'il soit nécessaire d'effectuer d'analyse topologique de l'application.

Dans cette partie, nous avons raisonné sur le modèle structurel rudimentaire élaboré en introduction. Il est en réalité beaucoup plus complexe. La partie suivante en décrira tous les détails.

DEUXIÈME

PARTIE

UN

MODÈLE

STRUCTUREL

CHAPITRE 4

COMPOSANTS, TÂCHES, VARIABLES

LE

MODÈLE

STRUCTUREL

Le modèle structurel d'NJN a été choisi pour faciliter le développement rapide d'applications distribuées. Il est orienté composant. Ce qui signifie qu'une application NJN est une construction hiérarchique élaborée à partir de composants standards, disponibles dans des bibliothèques. Les composants hébergent des tâches et des variables, seuls éléments qui laisseront leur marque dans l'exécutif. A ce modèle de base s'ajoutent quelques objets plus complexes à appréhender, les méthodes et les canaux, destinés à structurer les interconnexions ou à abstraire les communications au sein de l'application.

Ce chapitre expose les différents objets présents dans le modèle structurel d'NJN. Après une première partie générale où quelques repères sont posés, chaque famille d'objet est présentée avec ses caractéristiques essentielles. Le point de vue adopté est celui du développeur d'application. Le rôle des objets et leur comportement est décrit en détail. Quelques exemples de code viennent illustrer de façon concrète le propos.

1

Des composants qui hébergent des variables

et des tâches

Une application NJN est représentée par l'instance de composant de plus haut niveau dans la hiérarchie structurelle. Cette instance, souvent appelée « top », est elle-même composée d'instances d'autres composants interconnectées entre elles

82 - Chapitre 4

par des variables et des ports d'entrées/sorties. Les composants situés tout en bas de la hiérarchie, hébergent des tâches qui portent le code actif de l'application.