• Aucun résultat trouvé

La bibliothèque libuspi.so : réflexivité des primitives OS

5.4 Cas d’étude & prototypage sur un ORB commercial

5.4.3 La bibliothèque libuspi.so : réflexivité des primitives OS

Le sous ensemble de la méta-interfaceMetaRequestLifeCy le_V2que nous avons choisi d’implémenter cible essentiellement le cycle de vie des requêtes CORBA (réception, traite- ment, réponse), et la réification des activités de synchronisation de l’OS (prise et libération de verrous) liées à ce cycle de vie. Au niveau du système d’exploitation, le premier pas consiste donc à pouvoir intercepter et modifier le comportement des primitives de synchro- nisation et de communication du standard POSIX.

lass MetaMutex { publi :

int pthread_mutex_init (pthread_mutex_t *mutex, ..) ; int pthread_mutex_lo k (..) ;

int pthread_mutex_unlo k (..) ; [..℄

};

void SetMetaMutexForMutex(MetaMutex*, pthread_mutex_t*);

FIG. 5.20 :La classeMetaMutex

Pour atteindre cet objectif, nous avons utilisé une méthode largement répandue dite par interposition de bibliothèque (library shadowing) [Levine 1999], et disponible sur la plupart des plates-formes POSIX. Cette méthode nous a permis de définir deux méta-classes, MetaSo ketet MetaMutex. Ces méta-classes permettent de modifier de manière sélective le comportement de chaque verrou ou connexion d’un programme en lui associant une instance appropriée de l’une d’entre elles. L’extrait de code de la figure 5.20 donne un aperçu de l’interface de MetaMutex et de la méthode SetMetaMutexForMutex(..) qui

permet d’associer un verrou à un méta-verrou. De même une fonction SetMetaSo ket- ForSo ket(..)assure la même opération pour lesMetaSo ket.

Transcendance et contextes sémantiques

Les classesMetaMutex et MetaSo ketpermettent de sélectionner individuellement les connexions et les verrous d’un programme dont les appels seront réifiés et modifiés au méta-niveau. Cependant, comme nous l’avons expliqué dans la section 5.2.3 page 87, nous ne souhaitons réifier que l’activité de certains verrous, qui correspondent à des points de contention pour les requêtes de l’ORB. De même, nous ne sommes intéressés que par les connexions véhiculant des communications CORBA, alors qu’un programme peut utiliser des connexions pour de nombreuses autres activités. Il nous faut donc, pour pouvoir utiliser les classesMetaMutexetMetaSo ket, trouver un moyen pour sélectionner de manière portable et peu intrusive les connexions et les verrous d’un ORB qui sont pertinents pour la réplication .

Pour répondre à ce problème nous introduisons les notions de transcendance logicielle et de contexte sémantique. Nous empruntons au vocabulaire de la philosophie la notion de transcendance qui représente le

« caractère de ce qui se situe au-delà d’un domaine pris comme référence, qui est au-dessus et d’une nature radicalement supérieure ».

[ATILF 2003] La notion de transcendance logicielle renvoie au fait que, dans une organisation en couches, une opération à un niveau donné ne prend son sens que dans le contexte plus large de l’activité des niveaux supérieurs. L’ouverture d’une connexion peut par exemple être l’une des étapes de l’invocation d’une requête CORBA, mais elle peut aussi correspondre à l’envoi d’une requête vers un serveur graphique X-WINDOWS. Or ces deux situations sont complè- tement opaques pour quelqu’un qui n’observe le système qu’au niveau de sa couche réseau et n’a connaissance ni de la norme CORBA, ni du protocole X11. Le même phénomène se retrouve dans l’utilisation des verrous. Dit autrement, les couches les plus basses réalisent des actions dont elles ne peuvent comprendre le sens global pour le reste du système. La logique globale du système transcende les couches de bas niveau, dont l’activité prend dans le système un sens plus large que leur simple sémantique individuelle.

Le concept de transcendance va de pair avec ce que nous appellerons le contexte sé- mantique d’une opération. Ce « contexte sémantique » représente l’endroit dans le logiciel, souvent situé dans les niveaux supérieurs, où le sens pour le système d’une opération de bas niveau devient explicite pour un observateur extérieur. Pour pouvoir décider, lorsqu’une connexion ou un verrou est créé, si son comportement doit être réifié, nous avons besoin de connaître le contexte sémantique de cette création (la création d’une connexion s’opère par l’appel POSIXso ket(..); celle d’un verrou parpthread_mutex_init(..)).

La figure 5.21 page ci-contre illustre cette situation pour l’appel POSIX pthread_- mutex_init(), qui permet de créer un verrou exclusif. Le contexte sémantique A peut

par exemple correspondre à la création d’un verrou pour la gestion d’un compteur de références, et le contexteB, à la création d’un verrou pour la gestion des requêtes en attente

de traitement. Le verrou créé dans le contexte A n’a pas besoin d’être réifié puisqu’il ne

constitue pas ce que nous avons appelé un point de contention pour les requêtes. En revanche les opérations sur le verrou créé dans le contexte B doivent être réifiées au méta-niveau

en utilisant une MetaMutex adaptée. La figure 5.21 montre que du fait de l’organisation interne d’un ORB, le contexte sémantique d’un appel peut se révéler relativement éloigné dans la pile d’invocations qui le provoque. ORBACUS par exemple utilise les primitives de synchronisation de la bibliothèque JTCdont nous avons parlé page 102 (voir notamment la figure 5.18 page 103). Or les deux verrous créés à partir des contextes A et B sont

indistinguables dans cette bibliothèque (ceci est représenté sur la figure par le fait que les deux créations utilisent la même suite d’appels emboîtés). Il est donc impossible de décider dans la bibliothèqueJTCsi un verrou doit être réifié ou non.

[pthread_mutex_init()]

A B

appel de création

d'un verrou exclusif suite d'appels emboîtés contexte sémantique OS interface spécifique à l'ORB (bibliothèque pour ORBacus)JTC

FIG. 5.21 :Contextes sémantiques d’un appel de bas niveau (icipthread_mutex_init())

Afin de pouvoir faire circuler le contexte sémantique d’un appel OS à travers les dif- férentes couches qui séparent l’appel de son contexte, nous nous sommes inspirés des mécanismes de régulation qui existent en biologie végétale entre les racines et les feuilles d’une plante. Par exemple, en période de canicule,

« [l]es racines [d’une plante] sont capables de percevoir l’état de sécheresse du sol. Elles synthétisent alors une hormone de stress, l’acide abscissique, qui est véhiculée jusqu’aux feuilles par la sève et qui ferme les stomates, ce qui limite les pertes en eau. »

Thierry Simonneau, cité dans [Galus 2003] Les brins d’exécution constituent la « sève » d’un système logiciel complexe puisqu’ils « transportent » données et contrôle d’un niveau d’abstraction à l’autre, et permettent à un programme de « prendre racine » dans son environnement d’exécution. Nous avons donc choisi, à la manière de l’acide abscissique chez les plantes, de faire circuler des méta- marqueurs porteurs de sens sur les brins de notre ORB12. Ces méta-marqueurs (représentés par la classeMetaThreadInfopage suivante) circulent en « contrebande » des paramètres du programme original, et permettent de fournir de manière portable et non-intrusive des

12L’ajout transparent de données à un brin d’exécution est une fonctionnalité standard des modèles de program-

mation à activités multiples. Cette fonctionnalité est par exemple assurée dans la norme POSIX par la fonction

informations aux couches de bas niveaux sur le contexte dans lequel elles sont utilisées. Un tel ajout d’informations est très proche du traçage de causalité par talonnage (piggybacking) sur les messages d’un système réparti, très utilisé dans les algorithmes distribués (par exemple dans [Baldoni et al. 1997, Baldoni et al. 1998b]).

lass MetaThreadInfoType ; lass MetaThreadInfo { publi : MetaThreadInfo(MetaThreadInfoType* someType) ; void atta hToSelfThread() ; void deta hFromSelfThread() ; }; FIG. 5.22 :La classeMetaThreadInfo

Usines à méta-verrous et à méta-connexions

Nous utilisons la classeMetaThreadInfoque nous venons d’introduie pour ajouter aux classesMetaMutex et MetaSo ketla capacité de se fixer sur un brin d’exécution. Par hé- ritage multiple nous obtenons alors deux nouvelles « méta-classes »,ThreadMetaSo ketet ThreadMetaMutex(figure 5.23 ci-dessous).

MetaMutex ThreadMetaMutex

MetaSocket ThreadMetaSocket MetaThreadInfo

FIG. 5.23 :Diagramme de classes des méta-objets du niveau POSIX

ThreadMetaSo ketetThreadMetaMutexcombinent les caractéristiques deMetaThread- Info(pouvoir se fixer sur un brin) à celle de MetaSo ket et MetaMutex (pouvoir inter- cepter et modifier les appels de l’OS relatifs à la gestion des verrous et à la gestion des connexions).ThreadMetaMutexpar exemple est implémentée de telle sorte qu’elle inter- cepte toutes les créations de verrous effectuées par le brin auquel elle est attachée. Par défaut ThreadMetaMutex ne modifie pas la sémantique de création des verrous POSIX (la création est transmise à l’appel pthread_mutex_init d’origine), mais en modifiant par héritage le comportement deThreadMetaMutex(figure 5.24 page suivante), il devient possible d’imposer, par exemple, que tous les verrous créés par un brin donné durant une section particulière de code soient associés à uneMetaMutexspécifique au moment de leur création (sur la figure 5.24, tous les verrous créés sont associés à une instance de la classe Spe ifi MetaMutex, qui interceptera à l’avenir leurs opérations).

lass ModifiedThreadMetaMutex : publi ThreadMetaMutex { publi :

pthread_mutex_init( pthread_mutex_t *mutex, ..) {

// A- Comportement par défaut : l'appel // pthread_mutex_init d'origine

int result = ThreadMetaMutex::pthread_mutex_init( mutex, ..) ;

// B - Les opérations sur le verrou nouvellement réé (mutex) seront // dorénavant inter eptées par une instan e de Spe ifi MetaMutex. SetMetaMutexForMutex ( new Spe ifi MetaMutex, mutex ) ;

return result ; }

} ;

FIG. 5.24 :Principe de fonctionnement d’une usine à méta-verrous

La classe ModifiedThreadMetaMutex de la figure 5.24 crée des méta-verrous sur les nouveaux verrous créés par un brin. C’est donc une usine à méta-verrous. De la même manière, ThreadMetaSo ketpeut être utilisée pour définir des usines à méta-connexions, qui associent des méta-connexions aux nouvelles connexions créées par un brin.

La période durant laquelle un brin est contrôlé par une usine à méta-verrous ou une usine à méta-connexions est modulable, en utilisant les capacités d’attachement et de détachement deMetaThreadInfo(figure 5.22 page ci-contre).ThreadMetaSo ketet ThreadMetaMutex forment donc un canevas particulièrement puissant pour contrôler quels verrous et quelles connexions intercepter dans le système (ce que Kiczales appelle le contrôle d’impact, dont nous avons parlé page 28). Ce canevas forme la base de notre méta-interface multi-niveaux, que nous détaillons dans la section suivante.