Page professionnelle – Thomas Robert

Maître de Conférence

TP Tolérance aux fautes II

Implémentation du concept de Recovery block en C

Nous souhaitons que vous implémentiez un ensemble de fonctions et structures de données permettant de mettre à disposition
le principe de recovery block pour un code séquentiel de temps de réponse borné. Cette
implémentation devra être fournie en C
Rappel du principe :
Le recovery block repose sur le principe de diversification et redondance (séquentielle) d’exécution.
Une même fonction doit disposer de diverses implémentations. le recovery block enveloppe ces implémentation de sorte à soumettre un jeu de paramètre à la première fonction et détecter toute défaillance de cette dernière.
Dans le cas où une défaillance n’est pas détectée le RB transfert le résultat à l’appelant, sinon la version suivante est exécutée.
Nous supposerons dans un premier temps que nous souhaitons développer ce service pour des fonctions ayant toujours la même signature. :
long long <name > (long )

Pour expérimenter votre implémentation vous utiliserez les deux implémentations fact1 et fact2 de la fonction factorielle (l’une est défaillante, l’autre non (cas de défaillance par dépassement de capacité de représentation).

Vous trouverez le fichier objet facotrielle.o dans cette archive

https://trobert.wp.imt.fr/files/2019/12/factoriellev2.zip

Ainsi, nous avons le comportement suivant :
• Le recovery block exécute fact1 puis fact2 si le résultat ne passe pas le test résultat >0
• La réexécution doit restaurer la pile d’exécution, i.e. l’exécution de la fonction « améliorée » ne doit pas perturber l’exécution d’un programme classique.
Vous allez devoir utiliser le fichier objet factorielle.o qui contient l’implémentation en code binaire de fact1 et fact2 (de signature long long factX(long)).
Vous devez donc répéter ces signature dans votre code puis compiler en deux étapes :
gcc -c votrecode.c
gcc votrecode.o factorielle.o -o appli

A) Rappels

Pour la restauration d’état, nous vous demandons d’utiliser sigsetjmp et setlongjmp.

Vous pouvez positionnez le point de reprise en utilisant sigsetjmp plutôt que setjmp (cf. man sigsetjmp). Lors de l’appel à la fonction sigsetjmp on mettra le second paramètre à 1.

Vous pouvez déclencher la restauration d’état à partir de en utilisant la fonction siglongjmp.

En cas de problème cf https://inf104.wp.imt.fr/tp-signaux/

B) Implémentation du recovery block

1) Implémentez une fonction main ou vous appelez simplement fact1(4), puis affichez le résultat puis fact(30) et au final fact(-1).

fact2 retourne -1 pour les nombres négatifs et la valeur attendu jusqu’à n=21.

2) Utilisez la restauration d’état pour exécuter fact2 en cas de défaillance

3) Utilisez la déclaration de la structure rb_t pour implémenter le recovery block à partir de la restauration d’état en supposant alternative1= fact1 et alternative2=fact2.

Et le code de lancement suivant:

#include <stdio.h>
#include « RB.h »

int main(int argc, char* argv[]){
long long aux=0;
printf(« Initialisation du recovery block »);
rb_t myRB;
init(&myRB);
run(&myRB, 4, &aux);
printf(« la valeur de 4! est %lld », aux);
aux=0;
run(&myRB, 17, &aux);
printf(« la valeur de 17! est %lld »,aux);

if (run(&myRB, -1, &aux)==-1) /// cas d’erreur -1 =>failed
{
printf(« la valeur de ! est %lld »,aux);
}

}

Il est possible de déclarer une variable de type pointeur de fonction de la manière suivante. Si vous souhaitez définir une fonction de type int f (int) vous devez déclarer int (* pfrf) (int); pour que prtf soit un pointeur de f. Dans ce cas il est possible d’écrire ptff=f;

Créez un fichier RB.h avec le contenu suivant :

typedef struct {
long long (*alternative1)(long);
long long (*alternative2)(long);;
int (*acceptanceTest)(long long,long);
} rb_t ;

void init(rb_t*);
void run (rb_t *, long , long long*);

 

Créez un fichier RB.c qui contiendra le code permettant de créer votre recovery block. Ce code devra contenir l’implémentation des  fonctions

void run (rb_t *, long , long long*);

et void init(rb_t*);

Utilisez la structure suivante pour implémenter le principe du recovery block de manière générique en supposant que vous n’avez que des défaillances en valeur.

typedef struct {
long long (*alternative1)(long);
long long (*alternative2)(long);
int (*acceptanceTest)(long long,long);
} rb_t ;

Il y a défaillance en valeur si la fonction acceptanceTest retourne 0

Dans notre cas le test d’acceptation sera passé si le résultat est positif.

Autre mise en œuvre : http://people.cs.aau.dk/~apr/ITV-MD3/Seminar2/RecoveryBlocks/sorting.html