/*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D U S I M U L A T E U R D E M E M O I R E V I R T U E L L E */ /* A V E C N / 2 S E R V E U R S E T N / 2 C L I E N T S F O N C T I O N N A N T */ /* E N L E C T U R E / E C R I T U R E A V E C S Y N C H R O N I S A T I O N : */ /* */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * ** * * * * * ** * */ /* * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * */ /* * * * * ** * * * * * ** */ /* * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* */ /* ATTENTION : */ /* */ /* Ce fichier ('$xtc/nCube.21$I') est */ /* reference dans 'v $xiMd/nCube.21$I.$m4' */ /* a des fins de demonstration 'WWW'. */ /* */ /* */ /* Author of '$xtc/nCube.21$I' : */ /* */ /* Jean-Francois COLONNA (LACTAMME, AAAAMMJJhhmmss). */ /* */ /*************************************************************************************************************************************/ /*************************************************************************************************************************************/ /* */ /* I N C L U D E S S T A N D A R D S : */ /* */ /*************************************************************************************************************************************/ #include <fcntl.h> #include <stdio.h> #include <time.h> #define STANDARD_OUT \ 1 \ /* Sortie standard... */ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N S T R E S G E N E R A L E S : */ /* */ /*************************************************************************************************************************************/ #define PREMIER_ELEMENT \ 0 \ /* Premier element de tout... */ #define CLEAR \ 0 \ /* Valeur d'effacement generale... */ #define UNITE \ 1 \ /* Unite... */ #ifndef pNULL # define pNULL \ CLEAR \ /* Pointeur nul. On notera le changement en 'pNULL' (un "p" ajoute devant) qui a eu lieu le */ \ /* 20041103114722 a cause du fait que d'une part le nom anterieur est utilise par '$M4' */ \ /* ('v $xiMoG/GENERE.02$Y DNULL') et que d'autre part 'v $xiMd/nCube.21$I.$m4 nCube.21.P.I'. */ #else #endif #define RIEN \ CLEAR \ /* Absence... */ #define OK \ CLEAR \ /* Code de retour general... */ #define NOK \ (OK + UNITE) \ /* Negation de 'OK'... */ #define UNDEF \ 31415 \ /* Pour quelque chose d'indefini... */ /*************************************************************************************************************************************/ /* */ /* F O N C T I O N S D E B I B L I O T H E Q U E : */ /* */ /*************************************************************************************************************************************/ extern int atoi(); extern char *getenv(); extern clock_t clock(); extern int system(); extern void *malloc(); extern void free(); #define Malloc(pointeur,taille) \ { \ pointeur = malloc(taille); \ if (pointeur == pNULL) \ { \ fprintf(stderr,"\n impossible d'allouer de la memoire"); \ exit(); \ } \ else \ { \ } \ } \ /* Procedure d'allocation memoire... */ extern double pow(); #define PUISSANCE2(n) \ ((int)(0.001 + pow((double)(2),(double)(n)))) \ /* ATTENTION, d'une part, ne pas ecrire : */ \ /* */ \ /* ((int)pow((FLOTTANT)(2),(FLOTTANT)(n))) */ \ /* */ \ /* puisque la fonction 'pow(...)' est une fonction de la librairie C qui attend un argument */ \ /* en double precision, et d'autre part, il est imperatif d'ajouter un petit epsilon, car, */ \ /* en effet, la valeur donnee par 'PUISSANCE2(n)' est legerement inferieure a la valeur */ \ /* entiere attendue des que 'n' est plus grand que 2... */ #define Get(valeur_de_la_variable,nom_de_la_variable) \ { \ valeur_de_la_variable = atoi(getenv(nom_de_la_variable)); \ } \ /* Procedure de recuperation de variables d'environnement. */ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D E L A P R E C I S I O N : */ /* */ /*************************************************************************************************************************************/ #define CHAR \ unsigned char \ /* Type des images... */ #define iLONGUEUR_caractere \ (int)sizeof(CHAR) #define iLONGUEUR_entier \ (int)sizeof(int) #define FLOTTANT \ double #define iLONGUEUR_flottant \ (int)sizeof(FLOTTANT) /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D E B A S E D E S M E S S A G E S : */ /* */ /*************************************************************************************************************************************/ extern void whoami(); extern int nread(); extern int nwrite(); #define iITYPE \ UNDEF \ /* Type des operations 'read(...)' et 'write(...)', mais actuellement inutilise... */ #define iUNDEF \ UNDEF \ /* Valeur actuellement inutilisee de 'flag' des fonctions 'read(...)' et 'write(...)... */ #define ANY \ (-1) \ /* Numero d'un processeur quelconque... */ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D E L A M E M O I R E V I R T U E L L E G L O B A L E : */ /* */ /* */ /* Definition : */ /* */ /* Supposons que l'on dispose de 2xN */ /* processeurs. Cet ensemble est decoupe */ /* en deux sous-ensembles : d'une part */ /* celui des clients, et d'autre part */ /* celui des serveurs. Un client ne peut */ /* dialoguer qu'avec un serveur... */ /* */ /* */ /* */ /* ------------------------------------------------ */ /* | */ /* Memoire virtuelle : | (...) */ /* | */ /* ------------------------------------------------ */ /* */ /* /\ /\ /\ */ /* || || || */ /* || || || */ /* \/ \/ \/ */ /* */ /* -------- -------- -------- */ /* | | | | | | */ /* Serveurs : | P0==S0 | | P2==S1 | | P4==S2 | (...) */ /* | | | | | | */ /* -------- -------- -------- */ /* */ /* /\ /\ /\ */ /* || || || */ /* || || || */ /* \/ \/ \/ */ /* */ /* ------------------------------------------------ */ /* | */ /* | commutation (...) */ /* | */ /* ------------------------------------------------ */ /* */ /* /\ /\ /\ */ /* || || || */ /* || || || */ /* \/ \/ \/ */ /* */ /* -------- -------- -------- */ /* | | | | | | */ /* Clients : | P1==C0 | | P3==C1 | | P5==C2 | (...) */ /* | | | | | | */ /* -------- -------- -------- */ /* */ /* */ /* La memoire virtuelle est donc */ /* supportee par les serveurs uniquement */ /* et est lue et ecrite par les clients. */ /* A chaque Client 'C' est associe un */ /* serveur naturel 'S' (par exemple 'S2' */ /* est associe a 'C1'), mais cela ne limite */ /* aucunement les acces. Ainsi donc a un */ /* client 'C' est associe naturellement */ /* un fragment (dit "local") de la memoire */ /* virtuelle, dans lequel il aura interet */ /* travailler afin de limiter le trafic... */ /* */ /*************************************************************************************************************************************/ #define LOG2_TAILLE_MEMOIRE_VIRTUELLE \ 20 \ /* Logarithme en base 2 de la taille de la memoire virtuelle exprimee en octets. */ #define TAILLE_DE_LA_MEMOIRE_VIRTUELLE \ PUISSANCE2(LOG2_TAILLE_MEMOIRE_VIRTUELLE) \ /* Taille de la memoire virtuelle exprimee en octets ; celle-ci doit etre une puissance */ \ /* de 2, d'ou cette definition partant du logarithme... */ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D U M A P P I N G E N T R E L E S */ /* P R O C E S S E U R S E T L A M E M O I R E V I R T U E L L E : */ /* */ /*************************************************************************************************************************************/ #define PROCESSEURS \ (UNITE + UNITE) \ /* Nombre de types de processeurs (les "serveurs" et les "clients"). */ #define PREMIER_PROCESSEUR \ PREMIER_ELEMENT \ /* Numero du premier processeur. */ #define PAGE_0 \ PREMIER_ELEMENT \ /* Premiere page. */ #define ADRESSE_ABSOLUE_0 \ PREMIER_ELEMENT \ /* Premiere adresse absolue. */ #define ADRESSE_RELATIVE_0 \ PREMIER_ELEMENT \ /* Premiere adresse relative. */ #define PREMIER_SERVEUR \ PREMIER_PROCESSEUR \ /* Numero du premier serveur. */ #define NUMERO_DE_SERVEUR__NUMERO_DE_PROCESSEUR(serveur) \ ((PREMIER_PROCESSEUR + ((serveur) - PREMIER_SERVEUR) * PROCESSEURS) + RIEN) \ /* Fonction de passage d'un numero de serveur a un numero de processeur... */ #define NUMERO_DE_PROCESSEUR__NUMERO_DE_SERVEUR(processeur) \ (PREMIER_SERVEUR + ((processeur) - PREMIER_PROCESSEUR) / PROCESSEURS) \ /* Et inverse... */ #define PREMIER_CLIENT \ PREMIER_PROCESSEUR \ /* Numero du premier client. */ #define NUMERO_DE_CLIENT__NUMERO_DE_PROCESSEUR(client) \ ((PREMIER_PROCESSEUR + ((client) - PREMIER_CLIENT) * PROCESSEURS) + UNITE) \ /* Fonction de passage d'un numero de client a un numero de processeur... */ #define NUMERO_DE_PROCESSEUR__NUMERO_DE_CLIENT(processeur) \ (PREMIER_CLIENT + ((processeur) - PREMIER_PROCESSEUR) / PROCESSEURS) \ /* Et inverse... */ #define ADRESSE_ABSOLUE__NUMERO_DE_PAGE(adresse) \ (PAGE_0 + (((adresse) - ADRESSE_ABSOLUE_0) / taille_de_la_memoire_virtuelle_par_serveur)) \ /* Fonction donnant le numero d'une page de la memoire virtuelle... */ #define NUMERO_DE_PAGE__ADRESSE_ABSOLUE(page) \ (ADRESSE_ABSOLUE_0 + ((page) - PAGE_0) * taille_de_la_memoire_virtuelle_par_serveur) \ /* Et inverse... */ #define NUMERO_DE_PAGE__SERVEUR(page) \ (PREMIER_SERVEUR + ((page) - PAGE_0)) \ /* Fonction donnant le numero d'une page de la memoire virtuelle... */ #define SERVEUR__NUMERO_DE_PAGE(serveur) \ (PAGE_0 + ((serveur) - PREMIER_SERVEUR)) \ /* Et inverse... */ #define ADRESSE_ABSOLUE__PROCESSEUR(adresse) \ NUMERO_DE_SERVEUR__NUMERO_DE_PROCESSEUR(NUMERO_DE_PAGE__SERVEUR(ADRESSE_ABSOLUE__NUMERO_DE_PAGE(adresse))) \ /* Fonction donnant le numero dans [0,N-1] du processeur supportant une adresse absolue */ \ /* donnee dans la memoire virtuelle. */ #define PROCESSEUR__ADRESSE_ABSOLUE(processeur) \ NUMERO_DE_PAGE__ADRESSE_ABSOLUE(SERVEUR__NUMERO_DE_PAGE(NUMERO_DE_PROCESSEUR__NUMERO_DE_SERVEUR(processeur))) \ /* Et inverse... */ #define ADRESSE_ABSOLUE__ADRESSE_RELATIVE(adresse) \ (ADRESSE_RELATIVE_0 + (((adresse) - ADRESSE_ABSOLUE_0) % taille_de_la_memoire_virtuelle_par_serveur)) \ /* Fonction donnant l'adresse relative a l'interieur d'un processeur d'adresse absolue */ \ /* donnee dans la memoire virtuelle. */ #define EST_SERVEUR(processeur) \ (NUMERO_DE_SERVEUR__NUMERO_DE_PROCESSEUR(NUMERO_DE_PROCESSEUR__NUMERO_DE_SERVEUR(processeur)) == processeur) \ /* Test pour savoir si un processeur est un serveur de memoire virtuelle... */ #define EST_CLIENT(processeur) \ (! EST_SERVEUR(processeur)) \ /* Test pour savoir si un processeur est un client de memoire virtuelle... */ #define SERVEUR_NATUREL(client) \ NUMERO_DE_SERVEUR__NUMERO_DE_PROCESSEUR(NUMERO_DE_PROCESSEUR__NUMERO_DE_SERVEUR(client)) \ /* Numero du serveur associe naturellement a un client... */ #define CLIENT_NATUREL(serveur) \ NUMERO_DE_CLIENT__NUMERO_DE_PROCESSEUR(NUMERO_DE_PROCESSEUR__NUMERO_DE_CLIENT(serveur)) \ /* Numero du client associe naturellement a un serveur... */ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D E L A M E M O I R E V I R T U E L L E L O C A L E */ /* A S S O C I E E N A T U R E L L E M E N T A C H A Q U E C L I E N T : */ /* */ /*************************************************************************************************************************************/ #define DEBUT_DE_LA_MEMOIRE_VIRTUELLE_LOCALE \ PROCESSEUR__ADRESSE_ABSOLUE(SERVEUR_NATUREL(processeur_local)) \ /* Premier octet de la memoire virtuelle supportee par le serveur associe naturellement */ \ /* au processeur local. */ #define FIN_DE_LA_MEMOIRE_VIRTUELLE_LOCALE \ (DEBUT_DE_LA_MEMOIRE_VIRTUELLE_LOCALE + taille_de_la_memoire_virtuelle_par_serveur - UNITE) \ /* Dernier octet de la memoire virtuelle supportee par le serveur associe naturellement */ \ /* au processeur local. */ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D E S F O N C T I O N S D E C O M M U N I C A T I O N : */ /* */ /*************************************************************************************************************************************/ typedef struct fonctions { int code_fonction; int adresse_relative; int longueur; } fonctions; /* Bloc descriptif de la fonction demandee a un serveur... */ enum Liste_des_codes_des_fonctions { DEBUT=CLEAR ,FIN ,STORE ,LOAD ,SWAP }; /* Liste des fonctions reconnues... */ #define iLONGUEUR_FONCTIONS \ (int)sizeof(fonctions) \ /* Et nombre d'octets necessaires au codage... */ #define Read(processeur,octets_a_lire,nombre_d_octets_a_lire) \ { \ int itype; \ int iflag; \ int longueur; \ \ processeur_emetteur = MAPPING(processeur); \ processeur_attendu = processeur_emetteur; \ iflag = iUNDEF; \ itype = iITYPE; \ longueur = nread(octets_a_lire,nombre_d_octets_a_lire,&processeur_attendu,&itype,&iflag); \ \ if ( ((processeur_attendu != processeur_emetteur) && (processeur_emetteur != ANY)) \ || (longueur != nombre_d_octets_a_lire) \ ) \ { \ fprintf(stderr,"\n erreur de lecture"); \ fprintf(stderr,"\n processeur attendu=%d",processeur_attendu); \ fprintf(stderr,"\n processeur emetteur=%d",processeur_emetteur); \ fprintf(stderr,"\n nombre d'octets a lire=%d",nombre_d_octets_a_lire); \ fprintf(stderr,"\n nombre d'octets recuperes=%d",longueur); \ exit(); \ } \ else \ { \ } \ processeur_attendu = MAPPING_INVERSE(processeur_attendu); \ } \ /* Procedure generale de lecture... */ #define Write(processeur,octets_a_ecrire,nombre_d_octets_a_ecrire) \ { \ int itype; \ int iflag; \ int longueur; \ \ processeur_recepteur = MAPPING(processeur); \ itype = iITYPE; \ iflag = iUNDEF; \ longueur = nwrite(octets_a_ecrire,nombre_d_octets_a_ecrire,processeur_recepteur,itype,&iflag); \ } \ /* Procedure generale d'ecriture... */ static int il_faut_entrelacer=OK; /* Indique s'il faut entrelacer (=OK) ou pas (#OK)... */ #define ENTRELACAGE(adresse_absolue_octets) \ ((il_faut_entrelacer == OK) ? entrelacage(adresse_absolue_octets) : (adresse_absolue_octets)) \ /* Definition de la fonction d'entrelacage. Pour le supprimer, il suffit de definir : */ \ /* */ \ /* #define ENTRELACAGE(adresse_absolue_octets) \ */ \ /* adresse_absolue_octets */ \ /* */ #define validation_d_une_adresse(adresse_absolue_octets,nombre_d_octets) \ { \ if ( ((adresse_absolue_octets) / unite_d_entrelacage) \ != (((adresse_absolue_octets) + (nombre_d_octets) - UNITE) / unite_d_entrelacage) \ ) \ { \ fprintf(stderr \ ,"l'intervalle [%08x,%08x] n'est pas dans une unite d'entrelacage %08x\n" \ ,(adresse_absolue_octets) \ ,(adresse_absolue_octets) + (nombre_d_octets) - UNITE \ ,unite_d_entrelacage \ ); \ } \ else \ { \ } \ } \ /* Validation d'une adresse octets par rapport aux parametres d'entrelacage... */ #define Interface_load_store(fonction,adresse_absolue_octets,nombre_d_octets) \ int adresse_entrelacee=UNDEF; \ fonctions Fonction; \ \ adresse_entrelacee=ENTRELACAGE(adresse_absolue_octets); \ Fonction.code_fonction = fonction; \ Fonction.adresse_relative = ADRESSE_ABSOLUE__ADRESSE_RELATIVE(adresse_entrelacee); \ Fonction.longueur = nombre_d_octets; \ /* Definition des donnees communes a 'load(...)' et 'store(...)'. */ #define load(adresse_absolue_octets,octets_a_lire,nombre_d_octets_a_lire) \ { \ Interface_load_store(LOAD,adresse_absolue_octets,nombre_d_octets_a_lire); \ \ validation_d_une_adresse(adresse_absolue_octets,nombre_d_octets_a_lire); \ \ Write(ADRESSE_ABSOLUE__PROCESSEUR(adresse_entrelacee),&Fonction,iLONGUEUR_FONCTIONS); \ /* Transmission d'une demande de "load" de valeur... */ \ Read(ADRESSE_ABSOLUE__PROCESSEUR(adresse_entrelacee),octets_a_lire,Fonction.longueur); \ /* Recuperation de la valeur... */ \ } \ /* Procedure d'acces a la valeur de 'octets_a_lire' dans la memoire virtuelle... */ #define store(adresse_absolue_octets,octets_a_ecrire,nombre_d_octets_a_ecrire) \ { \ Interface_load_store(STORE,adresse_absolue_octets,nombre_d_octets_a_ecrire); \ \ validation_d_une_adresse(adresse_absolue_octets,nombre_d_octets_a_ecrire); \ \ Write(ADRESSE_ABSOLUE__PROCESSEUR(adresse_entrelacee),&Fonction,iLONGUEUR_FONCTIONS); \ /* Transmission d'une demande de "store" de valeur... */ \ Write(ADRESSE_ABSOLUE__PROCESSEUR(adresse_entrelacee),octets_a_ecrire,Fonction.longueur); \ /* Envoi de la valeur. */ \ } \ /* Procedure de rangement de la valeur de 'octets_a_ecrire' dans la memoire virtuelle... */ #define action_de_debut_pour_les_serveurs \ { \ } \ /* Procedure indiquant qu'un serveur va debuter son travail... */ #define action_de_fin_pour_les_serveurs \ { \ } \ /* Procedure indiquant qu'un serveur a fini son travail... */ #define action_de_debut_pour_les_clients \ { \ int processeur; \ \ for (processeur=PREMIER_PROCESSEUR ; processeur<(PREMIER_PROCESSEUR+nombre_total_processeurs) ; processeur++) \ { \ if (EST_SERVEUR(MAPPING(processeur))) \ { \ Interface_load_store(DEBUT,UNDEF,UNDEF); \ Write(processeur,&Fonction,iLONGUEUR_FONCTIONS); \ /* Transmission d'une demande de debut... */ \ Read(processeur,&Fonction,iLONGUEUR_FONCTIONS); \ /* Et synchronisation sur le serveur en recuperant tout simplement la fonction envoyee ; */ \ /* ainsi, on ne demarre un client que lorsque tous les serveurs sont prets... */ \ } \ else \ { \ } \ } \ } \ /* Procedure indiquant qu'un client va debuter son travail... */ #define action_de_fin_pour_les_clients \ { \ int processeur; \ \ for (processeur=PREMIER_PROCESSEUR ; processeur<(PREMIER_PROCESSEUR+nombre_total_processeurs) ; processeur++) \ { \ if (EST_SERVEUR(MAPPING(processeur))) \ { \ Interface_load_store(FIN,UNDEF,UNDEF); \ Write(processeur,&Fonction,iLONGUEUR_FONCTIONS); \ /* Transmission d'une demande de fin... */ \ } \ else \ { \ } \ } \ } \ /* Procedure indiquant qu'un client a fini son travail... */ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D E S F O N C T I O N S D E C O M M U N I C A T I O N : */ /* */ /*************************************************************************************************************************************/ #define MStoreC(adresse_absolue,longueur_octets,valeur) \ { \ store(((adresse_absolue)*iLONGUEUR_caractere),&valeur,longueur_octets); \ } \ /* Procedure de rangement d'un caractere. */ #define MLoadC(adresse_absolue,longueur_octets,valeur) \ { \ load(((adresse_absolue)*iLONGUEUR_caractere),&valeur,longueur_octets); \ } \ /* Procedure d'acces a un caractere. */ #define StoreC(adresse_absolue,valeur) \ { \ MStoreC(adresse_absolue,iLONGUEUR_caractere,valeur); \ } \ /* Procedure de rangement d'un caractere. */ #define LoadC(adresse_absolue,valeur) \ { \ MLoadC(adresse_absolue,iLONGUEUR_caractere,valeur); \ } \ /* Procedure d'acces a un caractere. */ #define MStoreI(adresse_absolue,longueur_octets,valeur) \ { \ store(((adresse_absolue)*iLONGUEUR_entier),&valeur,longueur_octets); \ } \ /* Procedure de rangement d'un nombre entier. */ #define MLoadI(adresse_absolue,longueur_octets,valeur) \ { \ load(((adresse_absolue)*iLONGUEUR_entier),&valeur,longueur_octets); \ } \ /* Procedure d'acces a un nombre entier. */ #define StoreI(adresse_absolue,valeur) \ { \ MStoreI(adresse_absolue,iLONGUEUR_entier,valeur); \ } \ /* Procedure de rangement d'un nombre entier. */ #define LoadI(adresse_absolue,valeur) \ { \ MLoadI(adresse_absolue,iLONGUEUR_entier,valeur); \ } \ /* Procedure d'acces a un nombre entier. */ #define MStoreF(adresse_absolue,longueur_octets,valeur) \ { \ store(((adresse_absolue)*iLONGUEUR_flottant),&valeur,longueur_octets); \ } \ /* Procedure de rangement d'un nombre flottant. */ #define MLoadF(adresse_absolue,longueur_octets,valeur) \ { \ load(((adresse_absolue)*iLONGUEUR_flottant),&valeur,longueur_octets); \ } \ /* Procedure d'acces a un nombre flottant. */ #define StoreF(adresse_absolue,valeur) \ { \ MStoreF(adresse_absolue,iLONGUEUR_flottant,valeur); \ } \ /* Procedure de rangement d'un nombre flottant. */ #define LoadF(adresse_absolue,valeur) \ { \ MLoadF(adresse_absolue,iLONGUEUR_flottant,valeur); \ } \ /* Procedure d'acces a un nombre flottant. */ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D E S F O N C T I O N S D E S Y N C H R O N I S A T I O N : */ /* */ /*************************************************************************************************************************************/ #define UNLOCK \ CLEAR \ /* Etat d'un verrou libre... */ #define LOCK \ (UNLOCK + UNITE) \ /* Etat d'un verrou occupe... */ #define TestAndSetI(adresse_absolue,valeur) \ { \ int valeur_a_forcer=valeur; \ /* Memorisation de la valeur que l'on desire forcer ; elle est rendue necessaire a cause */ \ /* de l'ordre du 'Read(...)' et du 'Write(...)' portant sur cette valeur... */ \ int adresse_absolue_en_octets=(adresse_absolue)*iLONGUEUR_entier; \ Interface_load_store(SWAP,adresse_absolue_en_octets,iLONGUEUR_entier); \ \ Write(ADRESSE_ABSOLUE__PROCESSEUR(adresse_entrelacee),&Fonction,iLONGUEUR_FONCTIONS); \ /* Transmission d'une demande de "swap" de valeur... */ \ Read(ADRESSE_ABSOLUE__PROCESSEUR(adresse_entrelacee),&valeur,Fonction.longueur); \ /* Recuperation de la valeur avant, */ \ Write(ADRESSE_ABSOLUE__PROCESSEUR(adresse_entrelacee),&valeur_a_forcer,Fonction.longueur); \ /* Puis envoi de la valeur apres... */ \ } \ /* Procedure d'echange d'un nombre entier afin de faire des synchronisations... */ #define WaitVerrou(verrou_global,verrou_local) \ { \ int verrou_local=LOCK; \ /* Definition de l'etat local du verrou global de protection d'une phase critique... */ \ while (verrou_local == LOCK) \ /* La premiere fois le verrou est a 1 afin de forcer le 'TestAndSetI(...)' qui suit. Ensuite */ \ /* tant qu'il reste a 1, cela signifie qu'il etait deja a 1 dans la memoire virtuelle, et */ \ /* donc qu'un autre processeur le possede deja... */ \ { \ TestAndSetI(verrou_global,verrou_local); \ /* Tentative d'entree dans une phase critique... */ \ } \ /* ATTENTION, on notera le desequilibre des "{" et des "}" afin que 'WaitVerrou(...)' et */ \ /* 'ClearVerrou(...)' forment une paire de parentheses... */ \ \ /* Procedure d'attente sur un verrou. */ #define ClearVerrou(verrou_global,verrou_local) \ /* ATTENTION, on notera le desequilibre des "{" et des "}" afin que 'WaitVerrou(...)' et */ \ /* 'ClearVerrou(...)' forment une paire de parentheses... */ \ verrou_local = UNLOCK; \ StoreI(verrou_global,verrou_local); \ /* Sortie de la phase critique... */ \ } \ /* Procedure de liberation d'un verrou... */ /*************************************************************************************************************************************/ /* */ /* M A P P I N G E N T R E L E S P R O C E S S E U R S */ /* L O G I Q U E S E T L E S P R O C E S S E U R S P H Y S I Q U E S */ /* P O U R L A M E M O I R E V I R T U E L L E : */ /* */ /*************************************************************************************************************************************/ static int il_faut_mapper=NOK; /* Indique s'il faut mapper (=OK) ou pas (#OK)... */ #define MAPPING(processeur) \ ((processeur == ANY) ? processeur : (*(mapping_des_processeurs+(processeur-PREMIER_PROCESSEUR)))) \ /* Fonction de mapping... */ #define MAPPING_INVERSE(processeur) \ ((processeur == ANY) ? processeur : (*(mapping_inverse_des_processeurs+(processeur-PREMIER_PROCESSEUR)))) \ /* Fonction de mapping inverse... */ static int *mapping_des_processeurs; static int *mapping_inverse_des_processeurs; /* Table de definition du mapping entre les processeurrs physiques et logiques. */ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D E S I M P L A N T A T I O N S */ /* D A N S L A M E M O I R E V I R T U E L L E : */ /* */ /*************************************************************************************************************************************/ #define UNITE_D_ENTRELACAGE \ iLONGUEUR_flottant static int unite_d_entrelacage=UNITE_D_ENTRELACAGE; /* Definition de la longueur des blocs qui ne doivent pas etre decoupes lors de l'operation */ /* d'entrelacage... */ #define FORMAT_DEBUT_DE_LA_MEMOIRE_VIRTUELLE \ iLONGUEUR_caractere #define LONGUEUR_DEBUT_DE_LA_MEMOIRE_VIRTUELLE \ CLEAR #define DEBUT_DE_LA_MEMOIRE_VIRTUELLE \ IMPLANTATION_EN_MEMOIRE_VIRTUELLE(ADRESSE_ABSOLUE_0 \ ,FORMAT_IMPLICITE_DE_LA_MEMOIRE_VIRTUELLE \ ,FORMAT_DEBUT_DE_LA_MEMOIRE_VIRTUELLE \ ) /* Emplacement du debut de la memoire virtuelle. */ #define FRONTIERE_COMMUNE \ unite_d_entrelacage \ /* Toutes les implantations en memoire virtuelle se feront sur des frontieres de 'FLOTTANT'. */ #define FORMAT_IMPLICITE_DE_LA_MEMOIRE_VIRTUELLE \ iLONGUEUR_caractere \ /* Pour definir le premier element implante dans la memoire virtuelle. */ #define MULTIPLE_SUPERIEUR(x,base) \ ((((x) + (base) - UNITE) / (base) ) * (base)) \ /* Calcul le multiple de 'base' immediatement superieur a 'x'... */ #define IMPLANTATION_EN_MEMOIRE_VIRTUELLE(adresse_precedente_plus_longueur,unite_precedente,unite_courante) \ (MULTIPLE_SUPERIEUR(((adresse_precedente_plus_longueur)*(unite_precedente)),FRONTIERE_COMMUNE) / (unite_courante)) \ /* Calcul de l'adresse d'implantation en memoire virtuelle de l'element courant en fonction */ \ /* de l'adresse d'implantation de l'element precedent et de leurs unites respectives. On */ \ /* notera que l'on se place de plus a une frontiere de 'FLOTTANT'. Enfin, l'adresse de */ \ /* l'objet courant est defini par rapport a l'objet precedent translate de la longueur de */ \ /* dernier, cette longueur etant exprimee dans l'unite 'unite_precedente' : ainsi, si par */ \ /* exemple l'objet precedent 'O1' est en entier, l'adresse de l'objet suivant 'O2' sera */ \ /* 'O1+1', et ce quel que soit le type de 'O2.'... */ #define ADRESSAGE_EN_MEMOIRE_VIRTUELLE(adresse_de_l_objet,deplacement) \ ((adresse_de_l_objet) + (deplacement)) \ /* Acces a un element 'deplacement' d'un objet 'adresse_de_l_objet'... */ /*************************************************************************************************************************************/ /* */ /* D O N N E E S G L O B A L E S : */ /* */ /*************************************************************************************************************************************/ static int processeur_local; /* Identite du processeur local. */ static int dimension; /* Dimension (0,1,2,...) de l'hyper-cube alloue. */ static int nproc; /* Donne dans les deux octets de poids faible la meme information que 'processeur_local', */ /* et dans les deux octets de poids forts le numero du process courant. */ static int nhost; /* Donne un identificateur 'ID' d'un programme host. */ static int nombre_total_processeurs; /* Nombre total de processeurs disponibles. */ static int nombre_total_de_serveurs; static int nombre_total_de_clients; /* Nombre total de serveurs et de clients. */ static int taille_de_la_memoire_virtuelle; /* Taille totale de la memoire virtuelle. */ static int taille_de_la_memoire_virtuelle_par_serveur; /* Taille de la memoire virtuelle supportee par chaque serveur. */ static int processeur_emetteur; static int processeur_recepteur; static int processeur_attendu; /*************************************************************************************************************************************/ /* */ /* F O N C T I O N D ' E N T R E L A C A G E D E S A D R E S S E S : */ /* */ /*************************************************************************************************************************************/ int entrelacage(adresse_absolue) int adresse_absolue; { int adresse_entrelacee=UNDEF; int numero_de_page=ADRESSE_ABSOLUE__NUMERO_DE_PAGE(adresse_absolue); int adresse_relative=ADRESSE_ABSOLUE__ADRESSE_RELATIVE(adresse_absolue); int bits_de_poids_faibles_de_l_adresse_relative=UNDEF; int bits_de_poids_forts_et_moyens_de_l_adresse_relative=UNDEF; int bits_de_poids_moyens_de_l_adresse_relative=UNDEF; int bits_de_poids_forts_de_l_adresse_relative=UNDEF; bits_de_poids_faibles_de_l_adresse_relative = (adresse_relative % unite_d_entrelacage); bits_de_poids_forts_et_moyens_de_l_adresse_relative = (adresse_relative / unite_d_entrelacage); bits_de_poids_moyens_de_l_adresse_relative = (bits_de_poids_forts_et_moyens_de_l_adresse_relative % nombre_total_de_serveurs); bits_de_poids_forts_de_l_adresse_relative = (bits_de_poids_forts_et_moyens_de_l_adresse_relative / nombre_total_de_serveurs); adresse_entrelacee = NUMERO_DE_PAGE__ADRESSE_ABSOLUE(SERVEUR__NUMERO_DE_PAGE(bits_de_poids_moyens_de_l_adresse_relative)) + ((bits_de_poids_forts_de_l_adresse_relative*nombre_total_de_serveurs) + numero_de_page)*unite_d_entrelacage + bits_de_poids_faibles_de_l_adresse_relative; /* Definition de l'entrelacage : */ /* */ /* ----------------------------------------------------------- */ /* | | | | | */ /* adresse absolue | numero | poids | poids | poids | */ /* non entrelacee | de page | forts | moyens | faibles | */ /* | | | | | */ /* ----------------------------------------------------------- */ /* . . . . . */ /* . . . . . */ /* . nombre . . nombre . longueur des . */ /* . de serveurs . . de serveurs . FLOTTANTs . */ /* . . . . . */ /* . . . */ /* . . taille de la memoire virtuelle par serveur . */ /* . . . */ /* */ /* # = # = */ /* # = # = */ /* # = # = */ /* # = # = */ /* # = # = */ /* # = */ /* # = # = */ /* # = # = */ /* # = # = */ /* # = # = */ /* # = # = */ /* */ /* ----------------------------------------------------------- */ /* | | | | | */ /* adresse absolue | poids | poids | numero | poids | */ /* entrelacee | moyens | forts | de page | faibles | */ /* | | | | | */ /* ----------------------------------------------------------- */ /* . . . . . */ /* . . . . . */ /* . nombre . . nombre . longueur des . */ /* . de serveurs . . de serveurs . FLOTTANTs . */ /* . . . . . */ /* . . . */ /* . . taille de la memoire virtuelle par serveur . */ /* . . . */ /* */ return(adresse_entrelacee); } /*************************************************************************************************************************************/ /* */ /* C O D E D E S S E R V E U R S : */ /* */ /*************************************************************************************************************************************/ serveur() { if (nombre_total_de_clients > RIEN) { if ( ( (taille_de_la_memoire_virtuelle_par_serveur >= iLONGUEUR_caractere) && (taille_de_la_memoire_virtuelle_par_serveur >= iLONGUEUR_entier) && (taille_de_la_memoire_virtuelle_par_serveur >= iLONGUEUR_flottant) && (taille_de_la_memoire_virtuelle_par_serveur >= unite_d_entrelacage) ) && ( ((taille_de_la_memoire_virtuelle_par_serveur % iLONGUEUR_caractere) == RIEN) && ((taille_de_la_memoire_virtuelle_par_serveur % iLONGUEUR_entier) == RIEN) && ((taille_de_la_memoire_virtuelle_par_serveur % iLONGUEUR_flottant) == RIEN) && ((taille_de_la_memoire_virtuelle_par_serveur % unite_d_entrelacage) == RIEN) ) ) { int nombre_de_clients_enregistres=CLEAR; /* Pour compter les clients qui se sont enregistres... */ int octet_courant; static CHAR *memoire_virtuelle; Malloc(memoire_virtuelle,taille_de_la_memoire_virtuelle_par_serveur); /* Allocation de la memoire virtuelle dans chaque serveur. */ for (octet_courant=(ADRESSE_RELATIVE_0) ; octet_courant<(ADRESSE_RELATIVE_0+taille_de_la_memoire_virtuelle_par_serveur) ; octet_courant++ ) { *(memoire_virtuelle+octet_courant) = CLEAR; /* Nettoyage initial non optimise (octet par octet) de la memoire virtuelle... */ } while (nombre_total_de_clients > RIEN) { fonctions fonction; Read(ANY,&fonction,iLONGUEUR_FONCTIONS); /* Recuperation de la fonction demandee par 'processeur_attendu' : */ switch((int)fonction.code_fonction) { case DEBUT: { Write(processeur_attendu ,&fonction ,iLONGUEUR_FONCTIONS ); /* Et on renvoie tout simplement la fonction... */ nombre_de_clients_enregistres++; /* On compte le nombre de processeurs enregistres. On notera qu'il est impossible de */ /* verifier simplement que 'nombre_de_clients_enregistres' atteint bien sa valeur maximale */ /* (c'est-a-dire 'nombre_total_de_clients'), car en effet, les demandes 'DEBUT' d'un certain */ /* client peuvent s'imbriquer avec les 'STORE' et 'LOAD' des autres, auquel cas les tests */ /* que l'on pourrait faire alors ne seraient pas definitifs, et donneraient donc des */ /* messages d'erreurs temporaires et non justifies... */ break; } case FIN: { nombre_total_de_clients--; /* On decremente le nombre de processeurs potentiels... */ break; } case STORE: { Read(processeur_attendu ,memoire_virtuelle+fonction.adresse_relative ,fonction.longueur ); /* Rangement dans la memoire virtuelle de la valeur demandee... */ break; } case LOAD: { Write(processeur_attendu ,memoire_virtuelle+fonction.adresse_relative ,fonction.longueur ); /* Transmission de la valeur demandee... */ break; } case SWAP: { Write(processeur_attendu ,memoire_virtuelle+fonction.adresse_relative ,fonction.longueur ); Read(processeur_attendu ,memoire_virtuelle+fonction.adresse_relative ,fonction.longueur ); /* Echange de la valeur demandee... */ break; } default: { fprintf(stderr ,"\n fonction non reconnue (code=%d)" ,(int)fonction.code_fonction ); break; } } } /* Fin d'activite du serveur... */ free(memoire_virtuelle); /* Desallocation de la memoire virtuelle dans chaque serveur. */ } else { fprintf(stderr,"\n la taille de la memoire virtuelle n'est pas adaptee aux structures manipulees"); fprintf(stderr,"\n chaque serveur supporte %x octets",taille_de_la_memoire_virtuelle_par_serveur); } } else { fprintf(stderr,"\n il faut au moins %d processeurs (1)",PROCESSEURS); fprintf(stderr,"\n ATTENTION, il est impossible de passer par ici"); /* ATTENTION, il est impossible de passer par ici a cause de la validation faite dans */ /* 'main()' au sujet de 'nombre_total_processeurs'... */ } return(OK); } /*************************************************************************************************************************************/ /* */ /* P R O G R A M M E P R I N C I P A L : */ /* */ /*************************************************************************************************************************************/ main() { /*************************************************************************************************************************************/ /* */ /* R E C U P E R A T I O N D E L A C O N F I G U R A T I O N D E " R U N " : */ /* */ /*************************************************************************************************************************************/ whoami(&processeur_local,&nproc,&nhost,&dimension); nombre_total_processeurs = PUISSANCE2(dimension); nombre_total_de_serveurs = nombre_total_processeurs/PROCESSEURS; nombre_total_de_clients = nombre_total_processeurs - nombre_total_de_serveurs; /* Recuperation de la configuration locale allouee. */ taille_de_la_memoire_virtuelle = TAILLE_DE_LA_MEMOIRE_VIRTUELLE; /* Taille totale de la memoire virtuelle. */ if (nombre_total_processeurs >= PROCESSEURS) { taille_de_la_memoire_virtuelle_par_serveur = taille_de_la_memoire_virtuelle / nombre_total_de_serveurs; /* Taille de la memoire virtuelle supportee par chaque serveur. */ if ((taille_de_la_memoire_virtuelle % nombre_total_de_serveurs) == RIEN) { int processeur; Malloc(mapping_des_processeurs,nombre_total_processeurs*iLONGUEUR_entier); Malloc(mapping_inverse_des_processeurs,nombre_total_processeurs*iLONGUEUR_entier); /* Allocation de la memoire virtuelle dans chaque serveur. */ for (processeur=(PREMIER_PROCESSEUR) ; processeur<(PREMIER_PROCESSEUR+nombre_total_processeurs) ; processeur++ ) { int processeurL=processeur; int processeurP=processeur; /* A priori, on initialise sur un "mapping" neutre (1 pour 1) pour la memoire virtuelle... */ if (il_faut_mapper == OK) { if (EST_SERVEUR(processeur)) { processeurP=PREMIER_PROCESSEUR +(nombre_total_processeurs-UNITE) -((processeur-PREMIER_PROCESSEUR)+UNITE); /* Cette definition inverse l'ordre des serveurs... */ } else { processeurP=PREMIER_PROCESSEUR +(nombre_total_processeurs-UNITE) -((processeur-PREMIER_PROCESSEUR)-UNITE); /* Cette definition inverse l'ordre des clients... */ } } else { } *(mapping_des_processeurs+(processeurL-PREMIER_PROCESSEUR)) = processeurP; *(mapping_inverse_des_processeurs+(processeurP-PREMIER_PROCESSEUR)) = processeurL; } /*************************************************************************************************************************************/ /* */ /* C O M M U N I C A T I O N : */ /* */ /*************************************************************************************************************************************/ if (EST_SERVEUR(MAPPING(processeur_local))) { action_de_debut_pour_les_serveurs; /* Action de debut... */ serveur(); /* Code specifique des serveurs. */ action_de_fin_pour_les_serveurs; /* Action de fin... */ } else { action_de_debut_pour_les_clients; /* Action de debut... */ client(); /* Code specifique des clients. */ action_de_fin_pour_les_clients; /* Action de fin... */ } /*************************************************************************************************************************************/ /* */ /* F I N D E S T R A I T E M E N T S : */ /* */ /*************************************************************************************************************************************/ free(mapping_inverse_des_processeurs); free(mapping_des_processeurs); } else { fprintf(stderr,"\n la taille de la memoire virtuelle est mauvaise"); } } else { fprintf(stderr,"\n il faut au moins %d processeurs (2)",PROCESSEURS); } exit(); }