/*************************************************************************************************************************************/
/* */
/* 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();
}