/*************************************************************************************************************************************/
/* */
/* G E S T I O N " E X T E R N E " D U P A R A L L E L I S M E : */
/* */
/* */
/* Utilisation : */
/* */
/* Cette commande s'utilisera par exemple */
/* de la facon suivante : */
/* */
/* if (`$xcg/parallele.01$X parallele=VRAI fichier=FICHIER` == $EXIST) then */
/* <BRANCHE_PARALLELE> */
/* else */
/* <BRANCHE_ALTERNATIVE> */
/* endif */
/* */
/* ou '<BRANCHE_PARALLELE>' represente ce */
/* qui peut etre parallelise puisque le verrou */
/* 'FICHIER$VERROU' a pu etre approprie par une */
/* MACHINE. En ce qui concerne les autres MACHINEs, */
/* elles continuent sur '<BRANCHE_ALTERNATIVE>' */
/* (eventuellement vide...). Cela correspond alors */
/* a l'ordonnancement suivant (par exemple) : */
/* */
/* */
/* | | | */
/* MACHINE_1 : | MACHINE_2 : | MACHINE_3 : | */
/* | | | */
/* ---------------------------+-----------------------------+-----------------------------+... */
/* | | | */
/* if (...) then | if (...) then | if (...) then | */
/* <SEQUENCE_1> | else | else | */
/* else | <RIEN> | <RIEN> | */
/* endif | endif | endif | */
/* | | | */
/* | | | */
/* if (...) then | if (...) then | if (...) then | */
/* else | <SEQUENCE_2> | else | */
/* <RIEN> | else | <RIEN> | */
/* endif | endif | endif | */
/* | | | */
/* | | | */
/* if (...) then | if (...) then | if (...) then | */
/* else | else | <SEQUENCE_3> | */
/* <RIEN> | <RIEN> | else | */
/* endif | endif | endif | */
/* | | | */
/* */
/* */
/* ou donc {<SEQUENCE_1>,<SEQUENCE_2>,<SEQUENCE_3>,...} */
/* s'executent en parallele sur {MACHINE_1,MACHINE_2,MACHINE_3,...}. */
/* */
/* */
/* Une autre utilisation est la suivante (introduite */
/* le 20070420094135) : */
/* */
/* if (`$xcg/parallele.01$X unique=VRAI fichier=FICHIER` == $EXIST) then */
/* <BRANCHE_UNIQUE> */
/* Fverrou FICHIER */
/* else */
/* endif */
/* */
/* ou '<BRANCHE_UNIQUE>' represente la branche */
/* qui doit etre a execution unique. Initialement, */
/* le fichier de nom 'FICHIER' n'existe pas ; la */
/* MACHINE qui s'approprie la branche via 'FICHIER$VERROU' */
/* doit, a la fin de "<BRANCHE_UNIQUE>" creer le fichier */
/* 'FICHIER' (en general en mode 'ro'...) via : */
/* */
/* Fverrou FICHIER */
/* */
/* en general. Les autres MACHINEs, pendant le temps */
/* d'execution de '<BRANCHE_UNIQUE>', sont en attente */
/* sur l'existence et le mode du fichier 'FICHIER'. */
/* Cela correspond alors a l'ordonnancement suivant */
/* (par exemple) : */
/* */
/* */
/* | | | */
/* MACHINE_1 : | MACHINE_2 : | MACHINE_3 : | */
/* | | | */
/* ---------------------------+-----------------------------+-----------------------------+... */
/* | | | */
/* | | | */
/* if (...) then | if (...) then | if (...) then | */
/* <SEQUENCE> | else | else | */
/* else | <ATTENTE> | <ATTENTE> | */
/* endif | endif | endif | */
/* | | | */
/* */
/* */
/* ou donc '<SEQUENCE>' ne s'execute que sur 'MACHINE_1', */
/* tandis que {MACHINE_2,MACHINE_3,...} attendent que */
/* 'MACHINE_1' ait fini l'execution de '<SEQUENCE>'. */
/* */
/* */
/* Nota : */
/* */
/* Dans l'etat actuel des choses (a la */
/* date du 1995051600), on peut considerer */
/* que l'on dispose des puissances de calcul */
/* suivantes : */
/* */
/* LACT12 SYSTEME_SGIND4GA_IRIX_CC : 1 */
/* LACT27 SYSTEME_SGIND524_IRIX_CC : 2 */
/* LACT28 SYSTEME_SGPCM801_IRIX_CC : 2 */
/* */
/* puis a la date du 19970212085116, des puissances */
/* de calcul suivantes (on notera que l'amelioration */
/* des performances de 'LACT27' remonte en fait a la */
/* date du 1996060400, lors de son passage a 250 MHz) : */
/* */
/* LACT12 SYSTEME_SGIND4GA_IRIX_CC : 1 */
/* LACT27 SYSTEME_SGIND524_IRIX_CC : 4 */
/* LACT28 SYSTEME_SGPCM801_IRIX_CC : 2 */
/* LACT29 SYSTEME_SGO200A1_IRIX_CC : 8 */
/* */
/* ou les valeurs numeriques (1, 2,...) donnent une */
/* quantite de travail dans une unite arbitraire... */
/* */
/* */
/* Nota : */
/* */
/* L'alias 'Gverrou' ('v $Fdivers Gverrou') permet */
/* de lister le contenu de chaque verrou '$v' */
/* et donc de savoir "qui a fait quoi...". */
/* */
/* */
/* ATTENTION : */
/* */
/* La commande '$xcg/parallele.01$X' ne */
/* doit pas s'utiliser avec les programmes */
/* faisant des calculs aleatoires, et par */
/* exemple : */
/* */
/* $xci/fract_2D.01$X, */
/* $xci/fract_3D.01$X, */
/* */
/* puisqu'en effet, les generateurs aleatoires */
/* de '$ximf/aleatoires$FON' sont tres dependants */
/* des machines ; le risque est donc d'avoir alors */
/* des resultats incompatibles entre-eux... */
/* */
/* */
/* Author of '$xcg/parallele.01$K' : */
/* */
/* Jean-Francois COLONNA (LACTAMME, 1995??????????). */
/* */
/*************************************************************************************************************************************/
/*===================================================================================================================================*/
/*************************************************************************************************************************************/
/* */
/* I N T E R F A C E ' listG ' : */
/* */
/* */
/* :Debut_listG: */
/* :Fin_listG: */
/* */
/*************************************************************************************************************************************/
/*===================================================================================================================================*/
/*************************************************************************************************************************************/
/* */
/* D I R E C T I V E S S P E C I F I Q U E S D E C O M P I L A T I O N : */
/* */
/*************************************************************************************************************************************/
/*===================================================================================================================================*/
/*************************************************************************************************************************************/
/* */
/* F I C H I E R S D ' I N C L U D E S : */
/* */
/*************************************************************************************************************************************/
#include INCLUDES_MINI
/*===================================================================================================================================*/
/*************************************************************************************************************************************/
/* */
/* P A R A M E T R E S : */
/* */
/*===================================================================================================================================*/
#define FAIRE_DU_PARALLELISME \
VRAI \
/* Faut-il faire du parallelisme ('VRAI') ou pas ('FAUX') ? */
#define EXECUTER_UNE_SEQUENCE_EN_PARALLELE \
VRAI \
/* Si 'IL_FAUT(faire_du_parallelisme)' s'agit-il d'executer une sequence en parallele */ \
/* ('VRAI') ou bien de garantir l'execution unique d'une sequence ('FAUX') ? Ceci fut */ \
/* introduit le 20070420094135... */
#if ( (defined(CMAP28)) \
)
/* Introduit le 20070423134356... */
# define PRE_METTRE_A_JOUR_LE_CACHE_DES_DIRECTORIES \
VRAI \
/* Si 'IL_NE_FAUT_PAS(executer_une_sequence_en_parallele)' faut-il tenter de pre-mettre */ \
/* a jour le cache des directories ('VRAI') ou pas ('FAUX') ? Ceci fut introduit le */ \
/* 20070423121234... */
#Aif ( (defined(CMAP28)) \
)
# define PRE_METTRE_A_JOUR_LE_CACHE_DES_DIRECTORIES \
FAUX \
/* Si 'IL_NE_FAUT_PAS(executer_une_sequence_en_parallele)' faut-il tenter de pre-mettre */ \
/* a jour le cache des directories ('VRAI') ou pas ('FAUX') ? Ceci fut introduit le */ \
/* 20070423121234... */
#Eif ( (defined(CMAP28)) \
)
#define TESTER_LE_MODE_DU_FICHIER \
VRAI
#define MODE_ATTENDU_POUR_LE_FICHIER \
Ftest_fichier_____MODE_r__
/* La possibilite de tester le mode du fichier, en plus de son existence, a ete introduite */
/* le 20070420152629. On notera que l'on choisi de tester par defaut l'existence du fichier */
/* 'nom_verrou_sans_le_postfixe_VERROU' avec en plus le mode 'r__' car, en effet, il s'agit */
/* de la solution la plus sure puisqu'un fichier peut etre cree en plusieurs fois, alors */
/* que son changement de mode (mode 'ro') est unique et ne peut avoir lieu qu'une fois le */
/* fichier completement cree... */
#define TEMPORISATION_D_ATTENTE_DE_LA_FIN_DE_LA_BRANCHE_A_EXECUTION_UNIQUE \
UN \
/* Temporisation d'attente de la fin de la branche a execution unique... */
/*===================================================================================================================================*/
/*************************************************************************************************************************************/
/* */
/* M A C R O S U T I L E S : */
/* */
/*************************************************************************************************************************************/
/*===================================================================================================================================*/
/*************************************************************************************************************************************/
/* */
/* G E S T I O N " E X T E R N E " D U P A R A L L E L I S M E : */
/* */
/*************************************************************************************************************************************/
BCommande(nombre_d_arguments,arguments)
/*-----------------------------------------------------------------------------------------------------------------------------------*/
Bblock
DEFV(CHAR,INIC(POINTERc(nom_verrou_sans_le_postfixe_VERROU),NOM_UNDEF_VIDE));
/* Nom du verrou a tester sans le postfixe '$VERROU'... */
DEFV(Logical,INIT(faire_du_parallelisme,FAIRE_DU_PARALLELISME));
/* Faut-il faire du parallelisme ('VRAI') ou pas ('FAUX') ? */
DEFV(Logical,INIT(executer_une_sequence_en_parallele,EXECUTER_UNE_SEQUENCE_EN_PARALLELE));
/* Si 'IL_FAUT(faire_du_parallelisme)' s'agit-il d'executer une sequence en parallele */
/* ('VRAI') ou bien de garantir l'execution unique d'une sequence ('FAUX') ? Ceci fut */
/* introduit le 20070420094135... */
DEFV(Logical,INIT(pre_mettre_a_jour_le_cache_des_directories,PRE_METTRE_A_JOUR_LE_CACHE_DES_DIRECTORIES));
/* Si 'IL_NE_FAUT_PAS(executer_une_sequence_en_parallele)' faut-il tenter de pre-mettre */
/* a jour le cache des directories ('VRAI') ou pas ('FAUX') ? Ceci fut introduit le */
/* 20070423121234... */
DEFV(Logical,INIT(tester_le_mode_du_fichier,TESTER_LE_MODE_DU_FICHIER));
DEFV(Positive,INIT(mode_attendu_pour_le_fichier,MODE_ATTENDU_POUR_LE_FICHIER));
/* La possibilite de tester le mode du fichier, en plus de son existence, a ete introduite */
/* le 20070420152629. On notera que l'on choisi de tester par defaut l'existence du fichier */
/* 'nom_verrou_sans_le_postfixe_VERROU' avec en plus le mode 'r__' car, en effet, il s'agit */
/* de la solution la plus sure puisqu'un fichier peut etre cree en plusieurs fois, alors */
/* que son changement de mode (mode 'ro') est unique et ne peut avoir lieu qu'une fois le */
/* fichier completement cree. */
/* */
/* On notera au passage les quelques modes utiles suivants : */
DEFV(Positive,INIT(mode_r__,Ftest_fichier_____MODE_r__));
DEFV(Positive,INIT(mode_r_x,Ftest_fichier_____MODE_r_x));
DEFV(Positive,INIT(mode_rw_,Ftest_fichier_____MODE_rw_));
DEFV(Positive,INIT(mode_rwx,Ftest_fichier_____MODE_rwx));
/* Pour aider... */
DEFV(Positive,INIT(temporisation_d_attente_de_la_fin_de_la_branche_a_execution_unique
,TEMPORISATION_D_ATTENTE_DE_LA_FIN_DE_LA_BRANCHE_A_EXECUTION_UNIQUE
)
);
/* Temporisation d'attente de la fin de la branche a execution unique... */
/*..............................................................................................................................*/
GET_ARGUMENTS_(nombre_d_arguments
,BLOC(GET_ARGUMENT_C("verrou=""v=""fichier=""V=",nom_verrou_sans_le_postfixe_VERROU);
GET_ARGUMENT_L("parallelisme=",faire_du_parallelisme);
GET_ARGUMENT_L("parallele=""multiple=",executer_une_sequence_en_parallele);
GET_ARGUMENT_N("unique=",executer_une_sequence_en_parallele);
GET_ARGUMENT_L("pmajcd=""pmaj=""cache_des_directories=",pre_mettre_a_jour_le_cache_des_directories);
GET_ARGUMENT_L("tm=""tester_mode=",tester_le_mode_du_fichier);
GET_ARGUMENT_X("mode=",mode_attendu_pour_le_fichier);
/* La procedure 'GET_ARGUMENT_X(...)' a remplace 'GET_ARGUMENT_I(...)' le 20070420185512... */
GET_ARGUMENT_Y("mode_r__=",mode_r__);
GET_ARGUMENT_Y("mode_r_x=",mode_r_x);
GET_ARGUMENT_Y("mode_rw_=",mode_rw_);
GET_ARGUMENT_Y("mode_rwx=",mode_rwx);
/* Pour aider a utiliser l'argument "mode=" (introduit le 20070424085256)... */
GET_ARGUMENT_I("temporisation=""tempo=""t="
,temporisation_d_attente_de_la_fin_de_la_branche_a_execution_unique
);
)
);
Test(IFNE_chaine(nom_verrou_sans_le_postfixe_VERROU,NOM_UNDEF_VIDE))
Bblock
ePARALLELE(BLOC(CAL2(Prin1("%d",Gval("EXIST")));)
/* On edite '$EXIST' si la branche "sequence_fondamentale" (ou "parallele") a ete empruntee, */
/* c'est-a-dire si le fichier 'nom_verrou_sans_le_postfixe_VERROU$VERROU' n'existait pas et */
/* a donc pu etre cree... */
/* */
/* On notera que l'on utilise 'Prin1(...)' (et non par 'Prer1(...)') a cause de l'usage qui */
/* est fait de cette edition. On verra par exemple : */
/* */
/* xivPdf 7 1 / 018363_018490 */
/* */
/* a ce propos... */
,BLOC(
Test(IL_FAUT(executer_une_sequence_en_parallele))
/* Cas de l'execution d'une sequence en parallele pour la branche "sequence_alternative" : */
/* */
/* cette branche rend alors la main immediatement (apres avoir edite "NEXIST" ci-apres). */
Bblock
Eblock
ATes
Bblock
/* Cas de l'execution unique d'une sequence pour la branche "sequence_alternative" : */
/* */
/* cette branche ne fait alors qu'attendre que la branche a execution unique soit terminee */
/* ce qui se manifeste par l'existence du fichier 'nom_verrou_sans_le_postfixe_VERROU'... */
DEFV(Logical,INIT(attendre_la_fin_de_la_branche_a_execution_unique,VRAI));
/* A priori, on va attendre... */
Tant(IL_FAUT(attendre_la_fin_de_la_branche_a_execution_unique))
Bblock
Test(PAS_D_ERREUR(Ftest_fichier_avec_pre_mise_a_jour_du_cache_des_directories
(nom_verrou_sans_le_postfixe_VERROU
,pre_mettre_a_jour_le_cache_des_directories
,NE_PAS_EDITER_LES_MESSAGES_D_ERREUR_DES_FICHIERS
)
)
)
/* Le 20070423095209 je note que si le fichier 'nom_verrou_sans_le_postfixe_VERROU' n'est */
/* pas local, mais appartient a un volume 'NFS', l'operation 'Ftest_fichier(...)' est une */
/* "lecture" dans un directory. Or les directories "distants" de type 'NFS' sont caches */
/* localement et ne sont pas mis a jour en temps reel (si une autre MACHINE que cette */
/* MACHINE locale ecrit dedans, et en particulier sur 'nom_verrou_sans_le_postfixe_VERROU'). */
/* Il semblerait que la mise a jour des directories "distants" de type 'NFS' soient faites */
/* systematiquement et periodiquement (toutes les 'N' secondes : 10, 20,... ?), peut-etre */
/* tout simplement par invalidation de leur contenu, provoquant ainsi leur relecture lors */
/* d'un acces a eux. Cela pourrait expliquer donc que le 'Ftest_fichier(...)' puisse */
/* renvoyer une erreur pendant plusieurs secondes (30 secondes sur 'sumix??.cluster) alors */
/* que le fichier 'nom_verrou_sans_le_postfixe_VERROU' existe malgre tout. */
/* */
/* En ce qui concerne les ecritures dans les directories, elles sont faites en temps reel */
/* sur les volumes 'NFS'. Ainsi, le 'Fstore_fichier_non_formatte(...)' que l'on trouve */
/* dans 'v $xig/defin_2$vv$DEF ePARALLELE', lui n'attend pas. */
/* */
/* Ainsi pour resumer : les ecritures 'NFS' dans les directories sont faites en temps reel, */
/* alors que les lectures (qui sont donc cachees) demandent un certain temps (plusieurs */
/* secondes...) pour etre valides... */
/* */
/* Le 20070423103314 je note qu'une solution pour eviter ce "delai" lors des lectures de */
/* directories dans 'Ftest_fichier(...)' pourrait etre de faire preceder le test d'existence */
/* de 'nom_verrou_sans_le_postfixe_VERROU' par l'ecriture d'un fichier temporaire situe dans */
/* le meme directory que le fichier 'nom_verrou_sans_le_postfixe_VERROU', ce qui forcerait */
/* alors la mise a jour du cache des directories. Cela fut introduit le 20070423121234 via */
/* la fonction 'Ftest_fichier_avec_pre_mise_a_jour_du_cache_des_directories(...)'. */
Bblock
/* Cas ou le fichier 'nom_verrou_sans_le_postfixe_VERROU' existe : */
Test(IL_FAUT(tester_le_mode_du_fichier))
Bblock
Test(EST_VALIDE(Ftest_fichier_____informations_utiles))
/* Test introduit le 20070424085256... */
Bblock
Test(IFEQ(Ftest_fichier_____mode,mode_attendu_pour_le_fichier))
Bblock
EGAL(attendre_la_fin_de_la_branche_a_execution_unique,FAUX);
/* Cas ou le fichier 'nom_verrou_sans_le_postfixe_VERROU' existe et a le mode attendu : on */
/* doit arreter d'attendre... */
Eblock
ATes
Bblock
Eblock
ETes
Eblock
ATes
Bblock
PRINT_ERREUR("les informations concernant le fichier sont invalides");
CAL1(Prer1("(il s'agit du fichier '%s')\n",nom_verrou_sans_le_postfixe_VERROU));
Eblock
ETes
Eblock
ATes
Bblock
EGAL(attendre_la_fin_de_la_branche_a_execution_unique,FAUX);
/* Cas ou le fichier 'nom_verrou_sans_le_postfixe_VERROU' existe et ou le mode est */
/* indifferent : on doit arreter d'attendre... */
Eblock
ETes
Eblock
ATes
Bblock
Eblock
ETes
Test(IL_FAUT(attendre_la_fin_de_la_branche_a_execution_unique))
Bblock
DODO(temporisation_d_attente_de_la_fin_de_la_branche_a_execution_unique);
/* Cas ou l'on doit attendre... */
Eblock
ATes
Bblock
Eblock
ETes
Eblock
ETan
Eblock
ETes
CAL2(Prin1("%d",Gval("NEXIST")));
)
/* On edite '$NEXIST' si c'est la branche "sequence_alternative" qui a ete empruntee, */
/* c'est-a-dire si le fichier 'nom_verrou_sans_le_postfixe_VERROU$VERROU' pre-existait... */
/* */
/* On notera que l'on utilise 'Prin1(...)' (et non par 'Prer1(...)') a cause de l'usage qui */
/* est fait de cette edition. On verra par exemple : */
/* */
/* xivPdf 7 1 / 018363_018490 */
/* */
/* a ce propos... */
,faire_du_parallelisme
,nom_verrou_sans_le_postfixe_VERROU
);
Eblock
ATes
Bblock
PRINT_ERREUR("le nom du verrou doit obligatoirement etre defini");
Eblock
ETes
RETU_Commande;
Eblock
ECommande