From 991dc2df52145828001259fd8064cff53d885b7a Mon Sep 17 00:00:00 2001 From: smas Date: Fri, 28 Jul 2000 14:13:54 +0000 Subject: [PATCH] =?UTF-8?q?Premi=C3=A8re=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/libshmem.doc | Bin 0 -> 72704 bytes doc/man3/libshmem.3 | 588 +++++++ include/shmem.h | 388 +++++ lib/libshmem.c | 3847 +++++++++++++++++++++++++++++++++++++++++++ lib/libshmem.h | 263 +++ util/smadmin.c | 341 ++++ 6 files changed, 5427 insertions(+) create mode 100644 doc/libshmem.doc create mode 100644 doc/man3/libshmem.3 create mode 100644 include/shmem.h create mode 100644 lib/libshmem.c create mode 100644 lib/libshmem.h create mode 100644 util/smadmin.c diff --git a/doc/libshmem.doc b/doc/libshmem.doc new file mode 100644 index 0000000000000000000000000000000000000000..485a7bf63c74d6dad22add101ac04a2609183d81 GIT binary patch literal 72704 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 f70Z4`o>0a_" +.LP +.BI "SMT_Status SM_Library_Open ( int " Instance ", const char * " Context_Name ", SMT_Flags " Open_Mode " );" +.LP +.BI "SMT_Status SM_Library_Instance_Get ( int * " Instance " );" +.LP +.BI "SMT_Status SM_Library_Context_Set ( char * " Context_Name " );" +.LP +.BI "SMT_Status SM_Library_Context_Get ( char ** " Context_Name " );" +.LP +.BI "SMT_Status SM_Library_Close ( SMT_Flags " Close_Mode " );" +.LP +.BI "SMT_Status SM_Library_Stderr_Set ( FILE * " Out " );" +.LP +.BI "SMT_Status SM_Heap_Exist ( char * " Heap_Name " );" +.LP +.BI "SMT_Status SM_Heap_Open ( char * " Heap_Name ", SMT_Heap ** " Heap ", size_t " Seg_Size " , SMT_Flags " Open_Flags ", int * " Locked " );" +.LP +.BI "SMT_Status SM_Heap_Close ( SMT_Heap * " Heap " );" +.LP +.BI "SMT_Status SM_Heap_End ( char * " Heap_Name " );" +.LP +.BI "SMT_Status SM_Heap_Compress ( SMT_Heap * " Heap ", size_t * " Size " );" +.LP +.BI "SMT_Status SM_Heap_Check ( SMT_Heap * " Heap ", int * " Nb_Detected " , int * " Nb_Corrected ", FILE * " Out " );" +.LP +.BI "SMT_Status SM_Heap_Lock ( SMT_Heap * " Heap ", SMT_Flags " Lock_Flags ", int * " Locked " );" +.LP +.BI "SMT_Status SM_Heap_Unlock ( SMT_Heap * " Heap " );" +.LP +.BI "SMT_Status SM_Heap_Config ( SMT_Heap * " Heap ", SMT_Tag " Tag ", ... );" +.LP +.BI "SMT_Status SM_Chunk_Alloc ( SMT_Heap * " Heap ", void ** " Ptr ", size_t " Size " );" +.LP +.BI "SMT_Status SM_Chunk_Free ( SMT_Heap * " Heap ", void * " Ptr " );" +.LP +.SH GENERALITES +.LP +La librairie LIBSM permet de gerer des espaces de memoire partagee. +Ces espaces de memoire partagee (notion de 'heap') sont references dans une base geree par la librairie. +.LP +La librairie permet de gerer plusieurs instances, chacune ayant une base qui lui est propre. +Pour chaque instance, des contextes d'utilisation pourront etre definis. +.LP +Les heaps sont constitues de blocs memoire (notion de 'chunk') qui pourront etre alloues et desalloues par les programmes y accedant de maniere concurrente. +.LP +Chaque heap presente la particularite d'etre : +.LP +.RS 3 +- identifie par un nom unique dans la base +.LP +- securise : les acces concurrents sont geres par l'utilisation de semaphores +.RS -3 +.LP +La librairie propose des fonctions de gestion : +.LP +.RS 3 +- de la base de la librairie (initialisation, ouverture, fermeture, destruction). +.LP +- des heaps (creation, ouverture, verrouillage, compression, deverrouillage, fermeture, destruction) +.LP +- des chunks (allocation, desallocation) +.RS -3 +.LP +.BI "BASE DE HEAPS" +.LP +La base constitue l'espace commun a tous les utilisateurs d'une instance de la librairie. +.LP +Cette base est initialisee une premiere fois et reference la liste de tous les heaps de l'instance. +.LP +Cette base est protegee par un systeme de verrou permettant de gerer les acces concurrents aux differents heaps. +.LP +.I NB +: la base contient un heap 'systeme' qui gere les ressources des autres heaps (dits heaps 'utilisateur'). +Ce heap 'systeme' est un heap prive qui ne devra pas etre accede directement par les utilisateurs de la librairie. +.LP +.BI "NOTION DE HEAP" +.LP +Un heap est un espace de memoire partagee reference dans la base. +Il y est identifie de maniere unique par son nom. +.LP +La notion de contexte d'utilisation permet de distinguer des heaps en prefixant leur nom par ce contexte. +.LP +Les acces concurrents aux ressources d'un heap sont geres par un systeme de verrou qui autorise : +.LP +.RS 3 +- plusieurs acces en lecture simultanes (verrous partages) +.LP +- un seul acces en ecriture (verrou exclusif) +.RS -3 +.LP +.I NB +: un verrouillage est opere en mode 'wait', ce qui signifie que les processus desirant verrouiller une ressource non disponible sera mis en attente jusqu'a sa mise en disponibilite. +.LP +.BI "NOTION DE CHUNK" +.LP +Un chunk est un bloc d'allocation memoire au sein d'un heap. +.LP +Un chunk appartient necessairement a une liste de chunks alloues au sein du heap (ACR) ou bien a celle de ses chunks libres (FCR). +.LP +.SH TYPES +.LP +La librairie met a la disposition des utilisateurs les types suivants : +.LP +.BI "SMT_Flags +.LP +.RS 3 +Ce type d'indicateur permet de preciser le mode d'ouverture d'une instance/d'un heap de la librairie. +.LP +.RS 3 +- +.B SMD_OPEN +: pour ouvrir une instance/un heap existante/existant +.LP +- +.B SMD_CREAT +: pour creer l'instance/le heap si elle/il n'existe pas +.LP +.RS -3 +.LP +Pour l'ouverture de la librairie, il permet en outre de preciser le mode de debugging : +.LP +.RS 3 +- +.B SM_DEBUG_NONE +: aucun message d'erreur n'est affiche +.LP +- +.B SM_DEBUG +: les messages d'erreur generes par la librairie LIBSHMEM sont affiches sur la sortie standard d'erreur +.LP +- +.B SM_DEBUG_ALL +: les messages d'erreur generes par toutes les librairies sous-jacentes a la LIBSHMEM sont affiches sur la sortie standard d'erreur +.RS -3 +.LP +Pour l'ouverture d'un heap, il permet de preciser son type de verrouillage : +.LP +.RS 3 +- +.B SMD_WRITE +: acces en ecriture (pose d'un verrou exclusif ) +.LP +- +.B SMD_READ +: acces en lecture (pose d'un verrou partage) +.LP +- +.B SMD_UNDEF +: aucun verrou. +.LP +.RS -3 +.RS -3 +.LP +.BI "SMT_Heap +.LP +.RS 3 +Ce type permet de designer un heap ouvert par le processus courant. +.LP +C'est le seul type concernant les heaps qui sera manipule par les utilisateurs a travers les API de la librairie. +.RS -3 +.LP +.SH FONCTIONS +.LP +.BI "SMT_Status SM_Library_Open ( int " Instance ", const char * " Context_Name ", SMT_Flags " Open_Mode " );" +.LP +.RS 3 +Cette fonction permet d'acceder aux ressources partagees d'une instance de la librairie (base de heap, heap 'systeme'). +Elle devra necessairement etre appelee par tout programme utilisant la librairie. +.LP +Cette fonction attend les parametres suivants : +.LP +.RS 3 +* (In) +.I Instance +: numéro de l'instance a ouvrir. +.LP +.I NB +: si cet argument vaut 0, alors c'est la variable d'environnement $INSTANCE qui definira le numéro de l'instance (1000 sinon). +.LP +* (In) +.I Context +: nom du contexte a utiliser. +.LP +.I NB +: si cet argument est NULL, alors c'est la variable d'environnement $CONTEXT qui definira le nom du contexte, ("CTX" sinon). +.LP +* (In) +.I Open_Mode +: le mode d'ouverture de l'instance ( +.B SMD_CREATE +pour la creation de l'instance, ou +.B SMD_OPEN +pour une ouverture simple) +.LP +.I NB +: cette valeur pourra etre combinee avec un mode de debugging ( +.B SMD_DEBUG_NONE +, +.B SMD_DEBUG +ou +.B SMD_DEBUG_ALL +) +.LP +.RS -3 +Outre l'acces aux ressources de l'instance, cette fonction provoque le verrouillage de la base en lecture. +L'utilisateur de la librairie est ainsi assure de l'existence de ces ressources tout au long de leur utilisation. +.LP +.I NB +: le mode d'ouverture +.B SMD_CREATE +est reserve aux administrateurs. +.RS -3 +.LP +.BI "SMT_Status SM_Library_Instance_Get ( int * " Instance " );" +.LP +.RS 3 +Cette fonction permet de recuperer dans l'argument +.I Instance +le numéro de l'instance utilisee. +.RS -3 +.LP +.BI "SMT_Status SM_Library_Context_Set ( char * " Context_Name " );" +.LP +.RS 3 +Cette fonction permet de definir +.I Context_Name +comme etant le nom du nouveau contexte d'utilisation de l'instance de la librairie LIBSHMEM. +.LP +.I NB +: specifier un contexte implique que tous les heaps manipules seront prefixes par le nom de ce contexte. +.RS -3 +.LP +.BI "SMT_Status SM_Library_Context_Get ( char ** " Context_Name " );" +.LP +.RS 3 +Cette fonction permet de recuperer dans l'argument +.I Context_Name +le nom du contexte utilise. +.RS -3 +.LP +.BI "SMT_Status SM_Library_Close ( SMT_Flags " Close_Flags " );" +.LP +.RS 3 +Cette fonction permet de fermer l'instance de la librairie LIBSM. +Elle libere egalement le verrou en lecture qui avait ete pose sur la base lors de l'ouverture de l'instance. +Cette fonction doit donc etre systematiquement appelee a la fin de chaque programme utilisant la librairie. +.LP +L'argument +.I Close_Flags +est le mode de fermeture de l'instance : +.LP +.RS 3 +- +.B SMD_CLOSE +pour fermer simplement l'instance +.LP +- +.B SMD_DESTROY +pour detruire en outre toutes les ressources de l'instance +.LP +.RS -3 +.LP +.I NB +: le mode de fermeture +.B SMD_DESTROY +est reserve aux administrateurs. +.LP +Bien entendu, la destruction des ressouces de l'instance ne sera pas possible tant qu'il existera d'autres processus utilisant la meme instance. +.RS -3 +.LP +.BI "SMT_Status SM_Library_Stderr_Set ( FILE * " Out " );" +.LP +.RS 3 +Cette fonction permet de definir +.I Out +comme la sortie standard des messages d'erreur generes par la librarie. +.RS -3 +.LP +.BI "SMT_Status SM_Heap_Exist ( char * " Heap_Name " );" +.LP +.RS 3 +Cette fonction permet de tester si un heap existe deja dans la base. +.LP +L'argument +.I Heap_Name +est le nom du heap a tester. +.LP +.RS -3 +.BI "SMT_Status SM_Heap_Open ( char * " Heap_Name ", SMT_Heap ** " Heap ", size_t " Seg_Size ", SMT_Flags " Open_Flags ", int * " Locked " );" +.LP +.RS 3 +Cette fonction permet d'ouvrir ou de creer un heap 'utilisateur' dans la base. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Heap_Name +: le nom du heap +.LP +* (Out) +.I Heap +: l'adresse d'un pointeur sur le heap a ouvrir +.LP +* (In) +.I Seg_Size +: la taille des segments qui composeront le heap (une fois le heap cree, cette taille peut etre modifiee via la fonction SM_Heap_Config). +.LP +.I NB +: si cet argument est nul, la taille sera par defaut de 102400 octets. +.LP +* (In) +.I Open_Flags +: le mode d'acces qui determine d'une part l'ouverture ou la creation du heap et d'autre part son type de verrouillage. +.LP +.I NB +: les deux valeurs +.B SMD_OPEN +et +.B SMD_CREATE +peuvent etre combinees. +.LP +* (In) +.I Locked +: un pointeur sur un indicateur de verrouillage : il indique si le verrou a effectivement ete pose ou si le heap etait deja verrouille dans ce mode +.RS -3 +.LP +.I NB +: le heap cree est constitue d'un seul segment de donnees et contient un unique chunk libre correspondant a ce premier segment de donnees. +.LP +.RS -3 +.LP +.BI "SMT_Status SM_Heap_Close ( SMT_Heap * " Heap ");" +.LP +.RS 3 +Cette fonction permet de fermer un heap ouvert. +.LP +Elle permet non seulement de detacher les ressources du heap du processus appelant, mais elle permet aussi de liberer le verrou pose lors de l'ouverture du heap. +.LP +L'argument +.I Heap +est un pointeur sur un heap ouvert. +.RS -3 +.LP +.BI "SMT_Status SM_Heap_End ( char * " Heap_Name " );" +.LP +.RS 3 +Cette fonction permet de detruire un heap. +.LP +L'argument +.I Heap_Name +designe le nom du heap a detruire. +.LP +.RS -3 +.BI "SMT_Status SM_Heap_Compress ( SMT_Heap * " Heap ", size_t * " Size " );" +.LP +.RS 3 +Cette fonction permet de compresser un heap, ce qui consiste a fusionner les chunks libres dont les adresses se suivent. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Heap +: un pointeur sur un heap ouvert +.LP +* (Out) +.I Size +: un pointeur sur la taille gagnee par compression +.RS -3 +.RS -3 +.LP +.BI "SMT_Status SM_Heap_Check ( SMT_Heap * " Heap ", int * " Nb_Detected " , int * " Nb_Corrected ", FILE * " Out " );" +.LP +.RS 3 +Cette fonction permet de corriger les structures qui constituent un heap dans le cas ou celles-ci contiendraient des incoherences. +.LP +Un rapport complet de toutes les erreurs detectees et corrigees sur chacune des structures du heap est affiche. +.LP +Elle doit recevoir les arguments suivants : +.RS 3 +.LP +* (In) +.I Heap +: un pointeur sur un heap ouvert +.LP +* (Out) +.I Nb_Detected +: un pointeur sur le nombre d'erreurs detectees +.LP +* (Out) +.I Nb_Corrected +: un pointeur sur le nombre d'erreurs corrigees +.LP +* (In) +.I Out +: un pointeur sur le flux de sortie du rapport +.LP +.RS -3 +.I NB +: cette fonction est automatiquement activee lors de l'ouverture d'un heap qui est dans un etat invalide (c.a.d un heap dont une mise a jour n'a pas ete a son terme). +.LP +Si toutes les erreurs detectees n'ont pas pu etre corrigees, le heap est declare corrompu et ne sera plus accessible par personne. +.LP +.RS -3 +.BI "SMT_Status SM_Heap_Lock ( SMT_Heap * " Heap ", SMT_Flags " Lock_Flags ", int * " Locked " );" +.LP +.RS 3 +Cette fonction permet de poser un verrou sur un heap. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Heap +: un pointeur sur un heap ouvert +.LP +* (In) +.I Lock_Flags +: le mode de verrouillage +.LP +* (Out) +.I Locked +: un pointeur sur un indicateur de verrouillage qui indique si le verrou a effectivement ete pose ou si le heap etait deja verrouille dans ce mode +.LP +.RS -3 +.I NB +: si le heap est deja verrouille avec le mode demande, alors l'indicateur de verrouillage sera valorise a FALSE. +.LP +Si le heap est deja verrouille avec un autre type de verrou, alors la fonction retournera +.B SMS_KO +. +.RS -3 +.LP +.BI "SMT_Status SM_Heap_Unlock ( SMT_Heap * " Heap " );" +.LP +.RS 3 +Cette fonction permet d'oter le verrou qui a ete pose sur un heap. +.LP +L'argument +.I Heap +est un pointeur sur le heap a deverrouiller. +.RS -3 +.LP +.BI "SMT_Status SM_Heap_Config ( SMT_Heap * " Heap ", SMT_Tag " Tag ", ... );" +.LP +.RS 3 +Cette fonction permet de configurer certain aspects d'un heap. +.LP +Elle doit recevoir les aruments suivants : +.LP +.RS 3 +* (In) +.I Heap +: un pointeur sur le heap a configurer. +.LP +* (In) +.I Tag +: le type de configuration +.LP +.RS 3 +- +.B SMD_SEGMENT_SIZE +: definition de la taille (en octets) des nouveaux segments de donnees qui composeront le heap (par defaut, les heaps sont composes de segments de 102 400 octets). +.LP +- +.B SMD_HEAP_LIMIT +: limitation de la taille totale des segments de donnees qui composent le heap (par defaut, un heap n'est pas limite en taille). +.LP +- +.B SMD_AUTO_COMPRESS +: nombre de chunks libres a partir duquel le heap est automatiquement compresse (la valeur SMD_NO_AUTO_COMPRESS permet de desactiver cette procedure automatique). +.LP +NB : cette limite est fixee par defaut a 1 000 chunks. +.LP +.RS -3 +.RS -3 +.RS -3 +.BI "SMT_Status SM_Chunk_Alloc ( SMT_Heap * " Heap ", void ** " Ptr ", size_t " Size " );" +.LP +.RS 3 +Cette fonction permet de reserver de la memoire dans un heap. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Heap +: un pointeur sur un heap ouvert +.LP +* (In) +.I Size +: la taille du chunk (en octets) +.LP +* (Out) +.I Ptr +: l'adresse du pointeur de chunk +.RS -3 +.LP +.RS -3 +.BI "SMT_Status SM_Chunk_Free ( SMT_Heap * " Heap ", void * " Ptr " );" +.LP +.RS 3 +Cette fonction permet de liberer de la memoire dans un heap. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Heap +: un pointeur sur un heap ouvert +.LP +* (In) +.I Ptr +: un pointeur de chunk +.RS -3 +.RS -3 +.LP +.SH CODE RETOUR +.LP +Toutes les fonctions constituant l'API de la librairie retourne une valeur de type +.B SMT_Status +: +.LP +.RS 3 +- +.B SMS_OK +: la fonction s'est correctement executee et a produit un resultat +.LP +- +.B SMS_KO +: la fonction s'est correctement executee mais n'a pas produit de resultat +.LP +- +.B SMS_ERRAPI +: la fonction a ete appelee avec des arguments de valeur incorrecte +.LP +- +.B SMS_ERRMEM +: la fonction ne s'est pas correctement executee pour un probleme d'allocation memoire +.LP +- +.B SMS_ERRSHM +: la fonction ne s'est pas correctement executee pour un probleme relatif a la memoire partagee +.LP +- +.B SMS_ERRSIG +: une operation sur semaphore a ete interrompue par un signal +.LP +- +.B SMS_ERRSEM +: la fonction ne s'est pas correctement executee pour un probleme relatif a l'utilisation des semaphores +.LP +.RS -3 +.I NB +: la macro +.B SM_ERROR() +permet de tester si un code retour correspond a une erreur. +.LP +En cas d'erreur, la variable +.B SM_Error_Msg +contient un message du type : +.LP +.RS 3 +Error : +.RS -3 +.LP +.I NB +: dans la mesure du possible, la librairie tente en cas de probleme de revenir a la situation precedant l'appel a la fonction. +.LP +Toutefois, pour les cas plus difficiles, la librairie propose une procedure de verification et de correction ( +.B SM_Heap_Check +) qui permet de corriger des incoherences sur les structures de donnees constituant un heap. +.RS -3 +.LP +.SH VOIR AUSSI +.B libnode +(3) diff --git a/include/shmem.h b/include/shmem.h new file mode 100644 index 0000000..131d1f9 --- /dev/null +++ b/include/shmem.h @@ -0,0 +1,388 @@ +#ifndef _LIBSM +#define _LIBSM + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* Code retour des fonctions constituant l'API */ + +typedef long SMT_Status; + +#define SMS_OK NDS_OK /* La fonction s'est correctement exécutée et a produit un résultat */ +#define SMS_KO NDS_KO /* La fonction s'est correctement exécutée mais n'a pas produit de résultat */ +#define SMS_NO_WAIT 2 /* Opération sur sémaphore en mode IPC_NOWAIT qui n'a pas pu aboutir */ + +#define SMS_YES SMS_OK /* Résultat booléen positif */ +#define SMS_NO SMS_KO /* Résultat booléen négatif */ + +#define SMS_ERRMEM NDS_ERRMEM /* Problème d'allocation mémoire */ +#define SMS_ERRAPI NDS_ERRAPI /* Utilisation incorrecte des API */ +#define SMS_ERRSHM -3 /* Problème relatif aux segments de mémoire partagée */ +#define SMS_ERRSEM -4 /* Problème relatif à l'utilisation des sémaphores */ +#define SMS_ERRSIG -5 /* Opération sur sémaphore interrompue par un signal */ + +#define SM_ERROR(s) ((s) < 0) /* Tous les codes retour négatifs correspondent à des erreurs */ + +typedef int SMT_Flags; + +#define SMD_UNDEF 0 + +/* Flags d'ouverture d'un heap ou d'une instance de la librairie */ + +#define SMD_CREATE 0x01 /* Création */ +#define SMD_OPEN 0x02 /* Ouverture simple */ +#define SMD_DESTROY 0x04 /* Destruction */ +#define SMD_CLOSE 0x08 /* Fermeture simple */ + +/* NB : pour l'ouverture de la librairie, les valeurs SMD_OPEN et SMD_CREATE sont mutuellement exclusives */ + +/* Flags de verrouillage */ + +#define SMD_READ 0x04 /* verrou partagé */ +#define SMD_WRITE 0x08 /* verrou exclusif */ +#define SMD_NO_LOCK 0x00 /* aucun verrou */ + +#define SMD_LOCK_MSK(a) ((a) & (SMD_READ|SMD_WRITE)) + +/* Mode de debug sur l'ouverture de la librairie */ + +#define SMD_DEBUG_NONE 0x00 /* pour n'afficher aucun message généré par les diverses librairies */ +#define SMD_DEBUG 0x10 /* pour afficher les messages générés par la librairie */ +#define SMD_DEBUG_ALL 0x20 /* pour afficher les messages générés par toutes les librairies sous-jacentes */ + +#define SMD_DEBUG_MSK(a) ((a) & (SMD_DEBUG|SMD_DEBUG_ALL)) + +/* Différentes types de configuration d'un heap */ + +typedef int SMT_Config; + +#define SMD_SEGMENT_SIZE 1 /* Définir la taille des segments */ +#define SMD_HEAP_LIMIT 2 /* Définir la taille maximale */ +#define SMD_AUTO_COMPRESS 3 /* Définir la taille d'un FCR à partir de laquelle + la compression du heap est autmatiquement activée */ + +#define SMD_DEFAULT_COMPRESS 1000 /* si + de 1000 chunks libres, alors compression du heap */ + +/* Différentes valeurs de configuration */ + +#define SMD_UNLIMITED 0 +#define SMD_NO_AUTO_COMPRESS 0 + +/* Nom du heap système */ + +#define HEAP_SYSTEM "system" + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +char SM_Error_Msg [512]; + +#ifndef SM_MODE +#define SM_MODE 0 +#endif + +#if SM_MODE == 1 /* API sans vérification des arguments */ + +#define SM_Library_Open SM_Library_Open_I +#define SM_Library_Instance_Get SM_Library_Instance_Get_I +#define SM_Library_Context_Set SM_Library_Context_Set_I +#define SM_Library_Context_Get SM_Library_Context_Get_I +#define SM_Library_Close SM_Library_Close_I +#define SM_Library_Dump SM_Library_Dump_I +#define SM_Library_Unlock SM_Library_Unlock_I +#define SM_Library_Stderr_Set SM_Library_Stderr_Set_I +#define SM_Heap_Exist SM_Heap_Exist_I +#define SM_Heap_Open SM_Heap_Open_I +#define SM_Heap_IsOpen SM_Heap_IsOpen_I +#define SM_Heap_Close SM_Heap_Close_I +#define SM_Heap_End SM_Heap_End_I +#define SM_Heap_Compress SM_Heap_Compress_I +#define SM_Heap_Config SM_Heap_Config_I +#define SM_Heap_Check SM_Heap_Check_I +#define SM_Heap_Lock SM_Heap_Lock_I +#define SM_Heap_Unlock SM_Heap_Unlock_I +#define SM_Chunk_Alloc SM_Chunk_Alloc_I +#define SM_Chunk_Free SM_Chunk_Free_I + +#else /* API avec vérification des arguments */ + +#define SM_Library_Open SM_Library_Open_C +#define SM_Library_Instance_Get SM_Library_Instance_Get_C +#define SM_Library_Context_Set SM_Library_Context_Set_C +#define SM_Library_Context_Get SM_Library_Context_Get_C +#define SM_Library_Close SM_Library_Close_C +#define SM_Library_Dump SM_Library_Dump_C +#define SM_Library_Unlock SM_Library_Unlock_C +#define SM_Library_Stderr_Set SM_Library_Stderr_Set_C +#define SM_Heap_Exist SM_Heap_Exist_C +#define SM_Heap_Open SM_Heap_Open_C +#define SM_Heap_IsOpen SM_Heap_IsOpen_C +#define SM_Heap_Close SM_Heap_Close_C +#define SM_Heap_End SM_Heap_End_C +#define SM_Heap_Compress SM_Heap_Compress_C +#define SM_Heap_Config SM_Heap_Config_C +#define SM_Heap_Check SM_Heap_Check_C +#define SM_Heap_Lock SM_Heap_Lock_C +#define SM_Heap_Unlock SM_Heap_Unlock_C +#define SM_Chunk_Alloc SM_Chunk_Alloc_C +#define SM_Chunk_Free SM_Chunk_Free_C + +#endif + +/*------------------------------------------------------------------------------*/ +/* Structure de la base de heaps */ +/*------------------------------------------------------------------------------*/ + +typedef struct { + int SysMemID; /* ID de la 1ère zone de mémoire partagée de la base */ + int DataMemID; /* ID de la 2ème zone de mémoire partagée de la base */ + size_t Size; /* Taille de la zone de mémoire partagée */ + int SemID; /* ID du sémaphore pour la gestion des verrous */ + NDT_Root * MHR; /* Memory Heap Root : racine de la liste de heap */ + pid_t Creator; /* ID du processus créateur de la base */ + pid_t Writer; /* ID du dernier processus ayant accédé en écriture à la base */ + void * Free; /* Pointeur sur la première zone libre de la base */ + void * Attach; /* Adresse du dernier attachement */ + size_t Segment_Size; /* Taille par défaut des segments qui composeront les heaps */ +} SMT_Base; + +/* Référence sur la base de heaps */ + +SMT_Base * SM_Base; + +/*------------------------------------------------------------------------------*/ +/* Structure d'un MHH (Memory Heap Header) */ +/* Rappel : un MHH est une valeur attachée à un MHN (Memory Heap Node) */ +/*------------------------------------------------------------------------------*/ + +typedef struct { + char Name [256]; /* Nom du heap */ + int SemID; /* ID du sémaphore pour la gestion des verrous */ + NDT_Root * DSR; /* Data Segment Root */ + NDT_Root * ACR; /* Allocated Chunks Root */ + NDT_Root * FCR; /* Free Chunks Root */ + pid_t Writer; /* ID du processus ayant accédé en dernier au MHH en écriture */ + int State; /* Etat d'un heap (valide, non validé ou corrompu) */ + size_t Segment_Size; /* Taille des segments de mémoire composant le heap */ + size_t Limit_Size; /* Taille limite du heap (par défaut : pas de limite) */ + int Auto_Compress; /* Nombre de chunks libres à partir duquel le heap est automatiquement compressé */ +} SMT_MHH; + +/* Heap ouvert */ + +typedef struct { + char * Name; + SMT_MHH * MHH; + SMT_Flags Lock_Mode; /* Mode dans lequel le heap est verrouillé */ + int Nb_Seg; /* Nombre de segments du heap lors de son ouverture */ +} SMT_Heap; + +/*------------------------------------------------------------------------------*/ +/* Structure d'un DSH (Data Segment Header) */ +/* Rappel : un DSH est une valeur attachée à un DSN (noeud de DSR) */ +/*------------------------------------------------------------------------------*/ + +typedef struct { + int MemID; /* ID de la zone de mémoire partagée */ + size_t Size; /* Taille de la zone de mémoire partagée */ + void * Start; /* Adresse de début de la zone de mémoire partagée */ +} SMT_DSH; + +/*------------------------------------------------------------------------------*/ +/* Structure d'un chunk */ +/* Rappel : un chunk est la valeur attachée à un noeud de ACR ou FCR */ +/*------------------------------------------------------------------------------*/ + +typedef struct { + size_t Size; /* Taille allouée au chunk */ + void * Data; /* Adresse de la zone de données du chunk */ +} SMT_Chunk; + +/*------------------------------------------------------------------------------*/ +/* Ouverture d'une instance de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Instance : numéro d'instance de la librairie */ +/* (I) Context : nom du nouveau contexte */ +/* (I) Flags : indicateur création/ouverture + mode d'affichage des erreurs */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Open_I ( int Instance, const char * Context, SMT_Flags Flags ); +SMT_Status SM_Library_Open_C ( int Instance, const char * Context, SMT_Flags Flags ); + +/*------------------------------------------------------------------------------*/ +/* Récupération du numéro de l'instance utilisée */ +/*------------------------------------------------------------------------------*/ +/* (O) Instance : adresse du numéro de l'instance utilisée */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Instance_Get_I ( int * Instance); +SMT_Status SM_Library_Instance_Get_C ( int * Instance); + +/*------------------------------------------------------------------------------*/ +/* Changement de contexte d'utilisation de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Context : nom du nouveau contexte */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Context_Set_I ( const char * Context ); +SMT_Status SM_Library_Context_Set_C ( const char * Context ); + +/*------------------------------------------------------------------------------*/ +/* Récupération du nom du contexte utilisé */ +/*------------------------------------------------------------------------------*/ +/* (O) Context : adresse du nom du contexte utilisé */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Context_Get_I ( char ** Context ); +SMT_Status SM_Library_Context_Get_C ( char ** Context ); + +/*------------------------------------------------------------------------------*/ +/* Fermeture de l'instance de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Flags : mode de fermeture (destruction ou fermeture simple) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Close_I ( SMT_Flags Flags ); +SMT_Status SM_Library_Close_C ( SMT_Flags Flags ); + +/*------------------------------------------------------------------------------*/ +/* Affichage des informations de la base de mémoires partagées */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : pointeur sur le flux de sortie */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Dump_I ( FILE * Out ); +SMT_Status SM_Library_Dump_C ( FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Libération de tous les verrous (base, heap) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Unlock_I ( void ); +SMT_Status SM_Library_Unlock_C ( void ); + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Stderr_Set_I ( FILE * Out ); +SMT_Status SM_Library_Stderr_Set_C ( FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Test d'existence d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap_Name : nom du heap */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Exist_I ( const char * Heap_Name ); +SMT_Status SM_Heap_Exist_C ( const char * Heap_Name ); + +/*------------------------------------------------------------------------------*/ +/* Ouverture/création d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap_Name : nom du heap */ +/* (O) Heap : pointeur sur le heap ouvert / créé */ +/* (I) Seg_Size : taille des segments du heap */ +/* (I) Flags : mode d'ouverture du heap */ +/* (O) Locked : verrou effectif (TRUE ou FALSE) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Open_I ( const char * Heap_Name, SMT_Heap ** Heap, size_t Seg_Size, SMT_Flags Flags, int * Locked ); +SMT_Status SM_Heap_Open_C ( const char * Heap_Name, SMT_Heap ** Heap, size_t Seg_Size, SMT_Flags Flags, int * Locked ); + +/*------------------------------------------------------------------------------*/ +/* Teste si un heap a déjà été ouvert par le processus courant */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap_Name : nom du heap */ +/* (O) Heap : adresse du pointeur sur le heap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_IsOpen_I ( const char * Heap_Name, SMT_Heap ** Heap ); +SMT_Status SM_Heap_IsOpen_C ( const char * Heap_Name, SMT_Heap ** Heap ); + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Close_I ( SMT_Heap * Heap ); +SMT_Status SM_Heap_Close_C ( SMT_Heap * Heap ); + +/*------------------------------------------------------------------------------*/ +/* Destruction d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap_Name : nom du heap */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_End_I ( const char * Heap_Name ); +SMT_Status SM_Heap_End_C ( const char * Heap_Name ); + +/*------------------------------------------------------------------------------*/ +/* Compression d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (O) Compress : pointeur sur la taille mémoire gagnée */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Compress_I ( SMT_Heap * Heap, size_t * Compress ); +SMT_Status SM_Heap_Compress_C ( SMT_Heap * Heap, size_t * Compress ); + +/*------------------------------------------------------------------------------*/ +/* Configuration d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Tag : type de configuration */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Config_I ( SMT_Heap * Heap, SMT_Config Tag, ... ); +SMT_Status SM_Heap_Config_C ( SMT_Heap * Heap, SMT_Config Tag, ... ); + +/*------------------------------------------------------------------------------*/ +/* Vérification/correction des structures d'un heap : */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (O) Nb_Detected : pointeur sur le nombre d'erreurs détectées */ +/* (O) Nb_Corrected : pointeur sur le nombre d'erreurs corrigées */ +/* (I) Out : pointeur sur le flux de sortie du rapport */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Check_I ( SMT_Heap * Heap, int * Nb_Detected, int * Nb_Corrected, FILE * Out); +SMT_Status SM_Heap_Check_C ( SMT_Heap * Heap, int * Nb_Detected, int * Nb_Corrected, FILE * Out); + +/*------------------------------------------------------------------------------*/ +/* Pose d'un verrou sur un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Flags : mode de verrouillage (SMD_READ ou SMD_WRITE) */ +/* (O) Locked : verrouillage effectué (TRUE ou FALSE) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Lock_I ( SMT_Heap * Heap, SMT_Flags Flags, int * Locked ); +SMT_Status SM_Heap_Lock_C ( SMT_Heap * Heap, SMT_Flags Flags, int * Locked ); + +/*------------------------------------------------------------------------------*/ +/* Libération d'un verrou sur un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Unlock_I ( SMT_Heap * Heap ); +SMT_Status SM_Heap_Unlock_C ( SMT_Heap * Heap ); + +/*------------------------------------------------------------------------------*/ +/* Allocation d'un chunk dans un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Size : taille du chunk */ +/* (O) Ptr : pointeur sur la zone de données allouée */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Chunk_Alloc_I ( SMT_Heap * Heap, size_t Alloc_Size, void ** Ptr ); +SMT_Status SM_Chunk_Alloc_C ( SMT_Heap * Heap, size_t Alloc_Size, void ** Ptr ); + +/*------------------------------------------------------------------------------*/ +/* Désallocation d'un chunk */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Ptr : adresse de la zone de données du chunk à désallouer */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Chunk_Free_I ( SMT_Heap * Heap, void * Ptr ); +SMT_Status SM_Chunk_Free_C ( SMT_Heap * Heap, void * Ptr ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libshmem.c b/lib/libshmem.c new file mode 100644 index 0000000..5250e2d --- /dev/null +++ b/lib/libshmem.c @@ -0,0 +1,3847 @@ +/* Utilisation des API de la LIBNODE sans vérification des arguments */ + +#define ND_MODE 1 + +#include + +VER_INFO_EXPORT(libshmem,"$Revision: 1.1 $", "$Name: $",__FILE__,"$Author: smas $") + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* FONCTIONS PUBLIQUES */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* FONCTIONS OPTIMISEES (SM_MODE = 1) */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Ouverture d'une instance de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Instance : numéro de l'instance de la librairie */ +/* (I) Context : nom du nouveau contexte */ +/* (I) Open_Mode : indicateur création/ouverture + mode d'affichage des erreurs */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Open_I ( int Instance, const char * Context, SMT_Flags Open_Mode ) +{ + SMT_Status rc; + int ND_Debug = FALSE; + int To_Open_Instance; + + /* Définition du mode d'affichage des messages d'erreur */ + + if (SMD_DEBUG_MSK(Open_Mode)) SM_stderr = stderr; + if (Open_Mode & SMD_DEBUG_ALL) ND_Debug = TRUE; + + /* Définition de l'instance à ouvrir */ + + if (Instance) To_Open_Instance = Instance; + else + { + if (!getenv (INSTANCE_ENV_VAR) || (To_Open_Instance = atoi (getenv (INSTANCE_ENV_VAR))) <= 0) + To_Open_Instance = DEFAULT_INSTANCE; + } + + if (Open_Mode & SMD_CREATE) /* Création d'une nouvelle instance */ + { + /* On vérifie que le processus courant n'accède pas déjà à une instance */ + + if (SM_Open_Counter > 0) + { + sprintf (SM_Error_Msg, "SM_Library_Open : the current process has already opened an instance (%d) of the LIBSHMEM base", SM_Instance); + SM_Error_Print (); + return SMS_ERRAPI; + } + + /* Ouverture de la librairie LIBNODE */ + + rc = ND_Library_Open (ND_Debug); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Library_Open : unable to open the LIBNODE library"); + SM_Error_Print (); + return rc; + } + + /* Ouverture de la liste des heaps ouverts (locale) */ + + rc = ND_DataStruct_Open (&Opened_Heap_List, NDD_DS_TREE | NDD_MN_AUTO_EQU, NULL, NULL, NULL, TRUE); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Library_Open : unable to create the local opened heap cache"); + SM_Error_Print (); + goto Error1; + } + else strcpy (Opened_Heap_List->Manager, "SM_Opened_Heap_List_Manager"); + + /* Création de la base de mémoire partagée */ + + SM_Instance = To_Open_Instance; + + rc = SM_Base_Init (); + if (rc != SMS_OK ) + { + sprintf (SM_Error_Msg, "SM_Library_Open : unable to initialize the shared memory base"); + SM_Error_Print (); + goto Error2; + } + } + else if (Open_Mode & SMD_OPEN) /* Ouverture d'une instance existante */ + { + /* On vérifie que le processus courant n'a pas déjà ouvert une autre instance */ + + if (SM_Open_Counter > 0 && To_Open_Instance != SM_Instance) + { + sprintf (SM_Error_Msg, "SM_Library_Open : the current process cannot open instance %d because it is already accessing instance %d", To_Open_Instance, SM_Instance); + SM_Error_Print (); + return SMS_ERRAPI; + } + + SM_Instance = To_Open_Instance; + + /* Ouverture effective si c'est la première fois */ + + if (SM_Open_Counter == 0) + { + /* Ouverture de la librairie LIBNODE */ + + rc = ND_Library_Open (ND_Debug); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Library_Open : unable to open the LIBNODE library"); + SM_Error_Print (); + return rc; + } + + /* Ouverture de la liste des heaps ouverts (locale) */ + + rc = ND_DataStruct_Open (&Opened_Heap_List, NDD_DS_TREE | NDD_MN_AUTO_EQU, NULL, NULL, NULL, TRUE); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Library_Open : unable to create the local opened heap cache"); + SM_Error_Print (); + goto Error1; + } + else strcpy (Opened_Heap_List->Manager, "SM_Opened_Heap_List_Manager"); + + /* Ouverture de la base de mémoire partagée */ + + rc = SM_Base_Open (); + if (rc != SMS_OK ) + { + sprintf (SM_Error_Msg, "SM_Library_Open : unable to open the shared memory base"); + SM_Error_Print (); + goto Error2; + } + } + } + + /* Définition du contexte */ + + SM_Library_Context_Set_I (Context); + + /* On incrémente le compteur d'ouverture de la librairie */ + + SM_Open_Counter++; + + return SMS_OK; + + /* Gestion d'erreur */ + + Error2: + ND_DataStruct_Close (Opened_Heap_List); + Error1: + ND_Library_Close (); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du numéro de l'instance utilisée */ +/*------------------------------------------------------------------------------*/ +/* (O) Instance : adresse du numéro de l'instance utilisée */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Instance_Get_I ( int * Instance ) +{ + *Instance = SM_Instance; + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du nom du contexte utilisé */ +/*------------------------------------------------------------------------------*/ +/* (O) Context : adresse du nom du contexte utilisé */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Context_Get_I ( char ** Context ) +{ + *Context = SM_Context; + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Changement de contexte d'utilisation de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Context : nom du nouveau contexte */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Context_Set_I ( const char * Context ) +{ + if (SM_Context) free (SM_Context); + + if (Context && strlen (Context)) SM_Context = strdup (Context); + else + { + if (getenv (CONTEXT_ENV_VAR) && strlen (getenv (CONTEXT_ENV_VAR))) + SM_Context = strdup (getenv (CONTEXT_ENV_VAR)); + else + SM_Context = strdup (DEFAULT_CONTEXT); + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture de l'instance de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Close_Mode : mode de fermeture (destruction ou fermeture simple) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Close_I ( SMT_Flags Close_Mode ) +{ + SMT_Status rc; + + if (Close_Mode & SMD_DESTROY) /* Destruction de l'instance */ + { + /* Destruction de la base de mémoire partagée */ + + rc = SM_Base_End (); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Library_Close: unable to destroy the shared memory base"); + SM_Error_Print (); + return rc; + } + + if (SM_Context) + { + free (SM_Context); + SM_Context = NULL; + } + + /* Fermeture de la liste des heaps ouverts */ + + ND_DataStruct_Close (Opened_Heap_List); + + /* Fermeture de la librairie LIBNODE */ + + ND_Library_Close (); + + /* Réinitialisation du compteur d'ouverture */ + + SM_Open_Counter = 0; + } + else if (Close_Mode & SMD_CLOSE) /* Fermeture de l'instance */ + { + /* + La fermeture n'est effective que si la librairie + n'a été ouverte qu'une seule fois. + */ + + if (SM_Open_Counter == 1) + { + /* Fermeture de la base de mémoire partagée */ + + rc = SM_Base_Close (); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Library_Close : unable to close the shared memory base"); + SM_Error_Print (); + return rc; + } + + if (SM_Context) + { + free (SM_Context); + SM_Context = NULL; + } + + /* Fermeture de la liste des heaps ouverts */ + + ND_DataStruct_Close (Opened_Heap_List); + + /* Fermeture de la librairie LIBNODE */ + + ND_Library_Close (); + } + + /* On met à jour le compteur d'ouverture de la librairie */ + + SM_Open_Counter--; + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Affichage des informations de la base de mémoires partagées */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Dump_I (FILE * Out) +{ + /* Affichage des informations sur la base */ + + fprintf (Out, "Base [%d/%s] :\n\t- Size = %d bytes\n\t- Creator pid = %ld\n\t- Last write access pid = %ld\n\t- ID Mem = %d (+%d)\n\t- ID Sem = %d\n\t- Status = %s\n\n", + SM_Instance, SM_Context, SM_Base->Size, SM_Base->Creator, SM_Base->Writer, SM_Base->SysMemID, SM_Base->DataMemID, SM_Base->SemID, SM_Lock_Status_Get ("base", SM_Base)); + + /* Affichage des informations du MHR */ + + ND_DataStruct_Info_Print (SM_Base->MHR, Out); + fprintf (Out, "\n"); + + /* Affichage des informations de chaque heap */ + + return ND_DataStruct_Print (SM_Base->MHR, Out); +} + +/*------------------------------------------------------------------------------*/ +/* Libération de tous les verrous (base, heap) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Unlock_I ( void ) +{ + NDT_Node * Node; + union semun Sem_Ctl; + + /* Libération des verrous sur la base */ + + Sem_Ctl.val = 1; + + if (semctl (SM_Base->SemID, 0, SETVAL, Sem_Ctl)) + { + sprintf (SM_Error_Msg, "SM_Library_Free : unable to unlock the shared memory base"); + SM_Error_Print (); + return SMS_ERRSEM; + } + + /* Libération des verrous sur les heaps */ + + ND_Node_First_Get (SM_Base->MHR, &Node); + + while (Node) + { + SMT_MHH * MHH; + + MHH = (SMT_MHH *)(Node->Value); + + if (semctl (MHH->SemID, 0, SETVAL, Sem_Ctl)) + { + sprintf (SM_Error_Msg, "SM_Library_Free : unable to unlock heap \"%s\"", MHH->Name); + SM_Error_Print (); + return SMS_ERRSEM; + } + + ND_Node_Next_Get (Node, &Node); + } + + ND_Node_First_Get (Opened_Heap_List, &Node); + + while (Node) + { + ((SMT_Heap *)(Node->Value))->Lock_Mode = SMD_NO_LOCK; + ND_Node_Next_Get (Node, &Node); + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Stderr_Set_I ( FILE * Out ) +{ + SM_stderr = Out; + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Test d'existence d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap_Name : Nom du heap */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Exist_I ( const char * Heap_Name ) +{ + NDT_Node * Node; + SMT_MHH * MHH; + char * Prefixed_Name = SM_Name_Prefix (Heap_Name); + int Locked = FALSE; + + if (strcmp (Heap_Name, HEAP_SYSTEM)) + { + /* Verrouillage du heap système en lecture */ + + SM_Heap_Lock_I (System_Heap, SMD_READ, &Locked); + } + + /* Recherche dans le MHR */ + + ND_Node_First_Get (SM_Base->MHR, &Node); + while (Node) + { + MHH = (SMT_MHH *)(Node->Value); + if (!strcmp (Prefixed_Name, MHH->Name)) return SMS_YES; + ND_Node_Next_Get (Node, &Node); + } + + /* Déverrouillage éventuel du heap système */ + + if (Locked == TRUE) SM_Heap_Unlock_I (System_Heap); + + return SMS_NO; +} + +/*------------------------------------------------------------------------------*/ +/* Ouverture/création d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap_Name : nom du heap */ +/* (O) Heap : pointeur sur le heap ouvert / créé */ +/* (I) Seg_Size : taille des segments du heap */ +/* (I) Open_Mode : mode d'ouverture du heap */ +/* (O) Locked : verrou effectif (TRUE ou FALSE) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Open_I ( const char * Heap_Name, SMT_Heap ** Heap, size_t Seg_Size, SMT_Flags Open_Mode, int * Locked ) +{ + SMT_MHH * MHH; + NDT_Node * Node; + SMT_DSH * New_DSH; + char * Prefixed_Name; + union semun Sem_Ctl; + int SemID; + SMT_Status rc; + + *Locked = FALSE; + + /* On regarde si le heap est déjà ouvert par le processus courant */ + + if (SM_Heap_IsOpen_I (Heap_Name, Heap) == SMS_YES) + { + if (Open_Mode & SMD_OPEN) + { + /* Verrouillage du heap dans le mode demandé */ + + rc = SM_Heap_Lock_I (*Heap, SMD_LOCK_MSK(Open_Mode), Locked); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to lock heap \"%s\" for %s", Heap_Name, Open_Mode & SMD_READ ? "reading" : "writing"); + SM_Error_Print (); + + return rc; + } + + return SMS_OK; + } + else + { + sprintf (SM_Error_Msg, "SM_Heap_Open : the heap already exists but (Flags & SMD_OPEN) is false"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + } + + Prefixed_Name = SM_Name_Prefix (Heap_Name); + + /* On regarde si le heap existe déjà dans la base */ + + if (SM_Heap_Exist_I (Heap_Name) == SMS_YES) + { + if (Open_Mode & SMD_OPEN) + { + /* Ouverture d'un heap existant */ + + SMT_MHH To_Find; + + strcpy (To_Find.Name, Prefixed_Name); + ND_Node_Find (SM_Base->MHR, &Node, &To_Find, NULL); + + MHH = (SMT_MHH *)(Node->Value); + + *Heap = (SMT_Heap *) malloc (sizeof (SMT_Heap)); + if (!*Heap) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to allocate memory for the opened heap \"%s\"", Prefixed_Name); + SM_Error_Print (); + + return SMS_ERRMEM; + } + + (*Heap)->Name = strdup (Prefixed_Name); + (*Heap)->MHH = MHH; + (*Heap)->Lock_Mode = SMD_NO_LOCK; + + /* On ouvre tous les segments du heap */ + + ND_Node_First_Get ((*Heap)->MHH->DSR, &Node); + while (Node) + { + rc = SM_DataSegment_Open (Node->Value); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to open one of the data segments of heap \"%s\"", Prefixed_Name); + SM_Error_Print (); + + goto Error1; + } + + ND_Node_Next_Get (Node, &Node); + } + + (*Heap)->Nb_Seg = (*Heap)->MHH->DSR->Node_Number; + + /* Verrouillage du heap dans le mode demandé */ + + rc = SM_Heap_Lock_I (*Heap, SMD_LOCK_MSK(Open_Mode), Locked); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to lock heap \"%s\" for %s", Prefixed_Name, Open_Mode & SMD_READ ? "reading" : "writing"); + SM_Error_Print (); + + goto Error1; + } + + /* Ajout au cache des heaps ouverts */ + + rc = ND_Value_Add (Opened_Heap_List, *Heap); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to add heap \"%s\" to the opened heap cache", Prefixed_Name); + SM_Error_Print (); + + goto Error2; + } + + return SMS_OK; + } + else + { + sprintf (SM_Error_Msg, "SM_Heap_Open : the heap already exists but (Open_Mode & SMD_OPEN) is false"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + } + + if (!(Open_Mode & SMD_CREATE)) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : the heap \"%s\" does no exist and (Open_Mode & SMD_CREATE) is false", Prefixed_Name); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + /* Création du sémaphore pour gérer les verrous sur le nouveau MHH */ + + SemID = semget (IPC_PRIVATE, 1, 0777|IPC_CREAT|IPC_EXCL); + if (SemID == -1) + { + switch (errno) + { + case ENOMEM: + sprintf (SM_Error_Msg, "SM_Heap_Open : the amount of memory is not sufficient to create a new semaphore"); + break; + + case ENOSPC: + sprintf (SM_Error_Msg, "SM_Heap_Open : the number of semaphores exceeds the system-imposed limit"); + break; + + default : + sprintf (SM_Error_Msg, "SM_Heap_Open : unknown error (%d) while creating a semaphore", errno); + break; + } + + SM_Error_Print (); + + return SMS_ERRSEM; + } + + /* Initialisation du sémaphore à 1 (équivaut à aucun verrou posé) */ + + Sem_Ctl.val = 1; + + if (semctl (SemID, 0, SETVAL, Sem_Ctl)) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to initialize the value of the semaphore %d", SemID); + SM_Error_Print (); + + rc = SMS_ERRSEM; + goto Error3; + } + + /* Réservation du MHH (dans la base pour le heap système, dans le heap système pour les autres heaps) */ + + if (ND_Allocator_Exec (SM_Base->MHR->Allocator, (void **)(&MHH), sizeof (SMT_MHH), NULL) != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to allocate memory for the heap header"); + SM_Error_Print (); + + rc = SMS_ERRSHM; + goto Error3; + } + + /* Initialisation de la structure du nouveau MHH */ + + strcpy (MHH->Name, Prefixed_Name); + MHH->Writer = getpid (); + MHH->SemID = SemID; + MHH->State = SMD_STATE_UNVALIDATED; + MHH->Segment_Size = (Seg_Size > 0 ? Seg_Size : SEGMENT_DEFAULT_SIZE); + MHH->Limit_Size = SMD_UNLIMITED; + MHH->Auto_Compress = SMD_DEFAULT_COMPRESS; + + /* + Création de la structure DSR : + - dans la base pour le heap système + - dans le heap système pour les autres heaps + */ + + rc = ND_DataStruct_Open (&(MHH->DSR), NDD_DS_LIST | NDD_MN_FIFO, SM_Base->MHR->Allocator, SM_Base->MHR->Desallocator, NULL, TRUE); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to create the DSR structure"); + SM_Error_Print (); + + goto Error4; + } + + strcpy (MHH->DSR->Manager, "SM_DSR_Manager"); + + /* + Création de la structure ACR : + - dans la base pour le heap système + - dans le heap système pour les autres heaps + */ + + rc = ND_DataStruct_Open (&(MHH->ACR), NDD_DS_LIST | NDD_MN_FIFO, SM_Base->MHR->Allocator, SM_Base->MHR->Desallocator, NULL, TRUE); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to create the ACR structure"); + SM_Error_Print (); + + goto Error5; + } + + strcpy (MHH->ACR->Manager, "SM_ACR_Manager"); + + /* + Création de la structure FCR : + - dans la base pour le heap système + - dans le heap système pour les autres heaps + */ + + rc = ND_DataStruct_Open (&(MHH->FCR), NDD_DS_LIST | NDD_MN_FIFO, SM_Base->MHR->Allocator, SM_Base->MHR->Desallocator, NULL, TRUE); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to create the FCR structure"); + SM_Error_Print (); + + goto Error6; + } + + strcpy (MHH->FCR->Manager, "SM_FCR_Manager"); + + /* Création d'un premier segment de données */ + + New_DSH = SM_DataSegment_Init (MHH, MHH->Segment_Size); + if (!New_DSH) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to create a data segment for the new heap"); + SM_Error_Print (); + + rc = SMS_ERRSHM; + goto Error7; + } + + rc = ND_Value_Add (MHH->DSR, New_DSH); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to add a data segment to the DSR structure"); + SM_Error_Print (); + + goto Error8; + } + + MHH->State = SMD_STATE_VALID; + + /* Ajout du nouveau heap à la structure MHR */ + + rc = ND_Value_Add (SM_Base->MHR, MHH); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to add the new heap to the MHR structure"); + SM_Error_Print (); + + goto Error9; + } + + /* Verrouillage du nouveau MHH dans le mode demandé */ + + rc = SM_Heap_Lock_Set (MHH, SMD_LOCK_MSK(Open_Mode)); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to lock heap \"%s\" for %s", + Prefixed_Name, Open_Mode & SMD_READ ? "reading" : "writing"); + SM_Error_Print (); + + goto Error10; + } + + *Locked = TRUE; + + /* Ajout du nouveau heap au cache des heaps ouverts */ + + *Heap = (SMT_Heap *) malloc (sizeof (SMT_Heap)); + if (!*Heap) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to allocate memory for a new opened heap \"%s\"", Prefixed_Name); + SM_Error_Print (); + rc = SMS_ERRMEM; + goto Error10; + } + + (*Heap)->Name = strdup (Prefixed_Name); + (*Heap)->MHH = MHH; + (*Heap)->Lock_Mode = SMD_LOCK_MSK(Open_Mode); + (*Heap)->Nb_Seg = 1; + + rc = ND_Value_Add (Opened_Heap_List, *Heap); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : unable to add heap \"%s\" to the opened heap cache", Prefixed_Name); + SM_Error_Print (); + goto Error11; + } + + return SMS_OK; + + /* Gestion d'erreur sur création */ + + Error11: + free ((*Heap)->Name); + free (*Heap); + *Heap = NULL; + Error10: + ND_Value_Remove (SM_Base->MHR, MHH, (void **)&MHH); + Error9: + ND_Value_Remove (MHH->DSR, New_DSH, (void **)&New_DSH); + Error8: + SM_DataSegment_End (MHH->DSR, New_DSH); + Error7: + ND_Desallocator_Exec (SM_Base->MHR->Desallocator, MHH->FCR, NULL); + Error6: + ND_Desallocator_Exec (SM_Base->MHR->Desallocator, MHH->ACR, NULL); + Error5: + ND_Desallocator_Exec (SM_Base->MHR->Desallocator, MHH->DSR, NULL); + Error4: + ND_Desallocator_Exec (SM_Base->MHR->Desallocator, MHH, NULL); + Error3: + semctl (SemID, 0, IPC_RMID, Sem_Ctl); + + return rc; + + /* Gestion d'erreur sur ouverture */ + + Error2: + SM_Heap_Unlock_I (*Heap); + Error1: + free ((*Heap)->Name); + free (*Heap); + *Heap = NULL; + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Teste si un heap a déjà été ouvert par le processus courant */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap_Name : Nom du heap */ +/* (O) Heap : pointeur sur le heap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_IsOpen_I ( const char * Heap_Name, SMT_Heap ** Heap ) +{ + SMT_Status rc; + + SMT_Heap To_Find; + NDT_Node * Node; + + *Heap = NULL; + + To_Find.Name = SM_Name_Prefix (Heap_Name); + + rc = ND_Node_Find (Opened_Heap_List, &Node, &To_Find, NULL); + + if (SM_ERROR(rc)) return rc; + + if (rc == NDS_KO) return SMS_NO; + + *Heap = (SMT_Heap *)(Node->Value); + return SMS_YES; +} + +/*------------------------------------------------------------------------------*/ +/* Destruction d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_End_I ( const char * Heap_Name ) +{ + SMT_Status rc; + SMT_Heap * Heap; + int Locked; + + rc = SM_Heap_Exist_I (Heap_Name); + if (SM_ERROR(rc)) return rc; + if (rc == SMS_NO) + { + sprintf (SM_Error_Msg, "SM_Heap_End: heap \"%s\" does not exist", Heap_Name); + SM_Error_Print (); + + return SMS_KO; + } + + rc = SM_Heap_IsOpen_I (Heap_Name, &Heap); + if (SM_ERROR(rc)) return rc; + if (rc == SMS_YES) + { + /* Verrouillage en écriture */ + + rc = SM_Heap_Lock_I (Heap, SMD_WRITE, &Locked); + } + else + { + /* Ouverture du heap en écriture */ + + rc = SM_Heap_Open_I (Heap_Name, &Heap, 0, SMD_OPEN | SMD_WRITE, &Locked); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_End : unable to open the heap to remove for writing"); + SM_Error_Print (); + + return rc; + } + } + + /* Suppression du heap */ + + rc = ND_Value_Remove (SM_Base->MHR, Heap->MHH, (void **)&(Heap->MHH)); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_End: unable to remove heap \"%s\" from the MHR structure", Heap_Name); + SM_Error_Print (); + + return rc; + } + + rc = ND_Value_Free (SM_Base->MHR, Heap->MHH); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_End: unable to free heap \"%s\"", Heap_Name); + SM_Error_Print (); + + return rc; + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Close_I ( SMT_Heap * Heap) +{ + SMT_Status rc; + NDT_Node * Node; + + /* + Fermeture des segments de données composant le heap + en commencant par le dernier (important pour le heap système) + */ + + ND_Node_Last_Get (Heap->MHH->DSR, &Node); + while (Node) + { + rc = SM_DataSegment_Close (Node->Value); + if (SM_ERROR(rc)) return rc; + + ND_Node_Previous_Get (Node, &Node); + } + + /* Déverrouillage du heap */ + + SM_Heap_Unlock_I (Heap); + + /* Suppression du heap de la liste des heaps ouverts */ + + rc = ND_Value_Remove (Opened_Heap_List, Heap, (void **)&Heap); + if (SM_ERROR(rc)) return rc; + + rc = ND_Value_Free (Opened_Heap_List, Heap); + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Pose d'un verrou sur un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Lock_Mode : mode de verrouillage (SMD_READ ou SMD_WRITE) */ +/* (O) Locked : verrouillage effectué (TRUE ou FALSE) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Lock_I ( SMT_Heap * Heap, SMT_Flags Lock_Mode, int * Locked ) +{ + SMT_Status rc; + int Nb_Detected, Nb_Corrected; + + if (Lock_Mode == Heap->Lock_Mode) + { + /* Rien à faire : le heap est déjà verrouillé dans ce mode */ + + *Locked = FALSE; + } + else if (Heap->Lock_Mode == SMD_NO_LOCK) + { + /* + Verrouillage d'un heap qui ne l'était pas : le heap ayant pu être modifié + depuis la dernière fois qu'on y a accédé, il faut procéder à un certain + nombre de vérifications. + */ + + /* Vérification de l'état du heap */ + + if (Heap->MHH->State == SMD_STATE_CORRUPTED) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock : heap \"%s\" is flagged as being corrupted", Heap->Name); + SM_Error_Print (); + + return SMS_KO; + } + + /* Verrouillage du heap dans le mode demandé */ + + rc = SM_Heap_Lock_Set (Heap->MHH, Lock_Mode); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock : unable to lock heap \"%s\" for %s", Heap->Name, Lock_Mode & SMD_READ ? "reading" : "writing"); + SM_Error_Print (); + + return rc; + } + + /* Vérification de l'état du heap */ + + if (Heap->MHH->State == SMD_STATE_UNVALIDATED) + { + /* Verrouillage du heap en écriture pour le vérifier */ + + if (Lock_Mode == SMD_READ) + { + rc = SM_Heap_Lock_Change (Heap->MHH, SMD_WRITE); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock : unable to lock heap \"%s\" for writing before checking", Heap->Name); + SM_Error_Print (); + + SM_Heap_Unlock_I (Heap); + return rc; + } + } + + /* Vérification du heap */ + + Nb_Detected = Nb_Corrected = 0; + rc = SM_Heap_Check_I (Heap, &Nb_Detected, &Nb_Corrected, SM_stderr); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock : unable to check heap \"%s\"", Heap->Name); + SM_Error_Print (); + + SM_Heap_Unlock_I (Heap); + return rc; + } + + /* On reverrouille éventuellement le heap dans le mode demandé */ + + if (Lock_Mode == SMD_READ) + { + rc = SM_Heap_Lock_Change (Heap->MHH, SMD_READ); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock : unable to lock heap \"%s\" for reading", Heap->Name); + SM_Error_Print (); + + SM_Heap_Unlock_I (Heap); + return rc; + } + } + } + + /* On vérifie qu'aucun nouveau segment n'a été ajouté depuis la dernière ouverture */ + + if (Heap->Nb_Seg != Heap->MHH->DSR->Node_Number) + { + NDT_Node * Node; + + /* On ouvre tous les segments du heap */ + + ND_Node_First_Get (Heap->MHH->DSR, &Node); + while (Node) + { + rc = SM_DataSegment_Open (Node->Value); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock : unable to open one of the data segments of heap \"%s\"", Heap->Name); + SM_Error_Print (); + + SM_Heap_Unlock_I (Heap); + return rc; + } + + ND_Node_Next_Get (Node, &Node); + } + + Heap->Nb_Seg = Heap->MHH->DSR->Node_Number; + } + + Heap->Lock_Mode = Lock_Mode; + *Locked = TRUE; + } + else + { + /* Verrouillage du heap qui est déjà verrouillé dans un autre mode */ + + rc = SM_Heap_Lock_Change (Heap->MHH, Lock_Mode); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock : unable to change lock of heap \"%s\" for %s", Heap->Name, Lock_Mode & SMD_READ ? "reading" : "writing"); + SM_Error_Print (); + + return rc; + } + + Heap->Lock_Mode = Lock_Mode; + *Locked = TRUE; + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Libération d'un verrou sur un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur unheap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Unlock_I ( SMT_Heap * Heap) +{ + SMT_Status rc; + + rc = SM_Heap_Lock_Release (Heap->MHH, Heap->Lock_Mode); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Unlock : unable to unlock heap \"%s\" for %s", + Heap->Name, Heap->Lock_Mode & SMD_READ ? "reading" : "writing"); + SM_Error_Print (); + + return rc; + } + + Heap->Lock_Mode = SMD_NO_LOCK; + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Configuration d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Tag : type de configuration */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Config_I ( SMT_Heap * Heap, SMT_Config Tag, ... ) +{ + va_list Arguments; + size_t Size, Current_Size; + SMT_Status rc; + + va_start (Arguments, Tag); + + switch (Tag) + { + case SMD_AUTO_COMPRESS: + + Size = va_arg (Arguments, size_t); + Heap->MHH->Auto_Compress = Size; + + break; + + case SMD_SEGMENT_SIZE: + + Size = va_arg (Arguments, size_t); + Heap->MHH->Segment_Size = Size; + + break; + + case SMD_HEAP_LIMIT: + + Size = va_arg (Arguments, size_t); + Current_Size = 0; + + if (Size != SMD_UNLIMITED) + { + /* On contrôle que la limite fixée est inférieure à la taille actuelle du heap */ + + rc = ND_DataStruct_Traverse (Heap->MHH->DSR, NDD_CMD_SUM_VALUES, (void *)&Current_Size); + if (rc != NDS_OK) return rc; + + if (Current_Size > Size) + { + sprintf (SM_Error_Msg, "SM_Heap_Config : the heap has already exceeded the limit size (%d bytes)", Current_Size); + SM_Error_Print (); + + va_end (Arguments); + return SMS_ERRAPI; + } + } + + Heap->MHH->Limit_Size = Size; + + break; + + default : + sprintf (SM_Error_Msg, "SM_Heap_Config : unknown config tag %d", Tag); + SM_Error_Print (); + + va_end (Arguments); + return SMS_ERRAPI; + } + + va_end (Arguments); + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Compression d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (O) Compress : pointeur sur la taille mémoire gagnée */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Compress_I ( SMT_Heap * Heap, size_t * Compress) +{ + SMT_Status rc; + NDT_Node * Node; + + *Compress = 0; + + /* + Pour permettre la compression, il faut que les + chunks libres soient triés par adresse. + */ + + rc = ND_DataStruct_Reorg (Heap->MHH->FCR); + if (rc != NDS_OK) return rc; + + /* Compression de chaque segment de données du heap */ + + ND_Node_First_Get (Heap->MHH->DSR, &Node); + while (Node) + { + *Compress += SM_DataSegment_Compress ((SMT_DSH *)(Node->Value), Heap->MHH->FCR); + ND_Node_Next_Get (Node, &Node); + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Vérification/correction des structures d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (O) Nb_Detected : pointeur sur le nombre d'erreurs détectées */ +/* (O) Nb_Corrected : pointeur sur le nombre d'erreurs corrigées */ +/* (I) Out : pointeur sur le flux de sortie du rapport */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Check_I ( SMT_Heap * Heap, int * Nb_Detected, int * Nb_Corrected, FILE * Out) +{ + SMT_Status rc; + NDT_Node * Node; + + if (Out) fprintf (Out, "Checking heap \"%s\" ...\n", Heap->Name); + + if (Heap->MHH->DSR->Node_Number == 0) + { + sprintf (SM_Error_Msg, "SM_Heap_Check : unable to check heap \"%s\" which has no data segment", Heap->Name); + SM_Error_Print (); + + (*Nb_Detected) ++; + + if (Out) fprintf (Out, "%d error(s) could not be corrected in heap \"%s\" which will be declared as corrupted.\n Please contact an administrator about it.\n", *Nb_Detected - *Nb_Corrected, Heap->Name); + Heap->MHH->State = SMD_STATE_CORRUPTED; + + return SMS_ERRAPI; + } + else + { + /* Vérification de la structure DSR du heap */ + + if (Out) fprintf (Out, "Checking the DSR node structure ...\n"); + + rc = ND_DataStruct_Check (Heap->MHH->DSR, Nb_Detected, Nb_Corrected, Out); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Check : unable to check the DSR structure"); + SM_Error_Print (); + + if (Out) fprintf (Out, "%d error(s) could not be corrected in heap \"%s\" which will be declared as corrupted.\n Please contact an administrator about it.\n", *Nb_Detected - *Nb_Corrected, Heap->Name); + Heap->MHH->State = SMD_STATE_CORRUPTED; + + return rc; + } + } + + fprintf (Out, "Trying to open every data segment of the heap ...\n"); + + /* Ouverture des segments du heap au cas ça n'aurait pas été fait */ + + ND_Node_First_Get (Heap->MHH->DSR, &Node); + + while (Node) + { + rc = SM_DataSegment_Open (Node->Value); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Check : unable to open one of the data segments of heap \"%s\"", Heap->Name); + SM_Error_Print (); + + (*Nb_Detected) ++; + + if (Out) fprintf (Out, "%d error(s) could not be corrected in heap \"%s\" which will be declared as corrupted.\n Please contact an administrator about it.\n", *Nb_Detected - *Nb_Corrected, Heap->Name); + Heap->MHH->State = SMD_STATE_CORRUPTED; + + return rc; + } + + ND_Node_Next_Get (Node, &Node); + } + + /* Vérification de la structure ACR du heap */ + + if (Out) fprintf (Out, "Checking the ACR node structure ...\n"); + + rc = ND_DataStruct_Check (Heap->MHH->ACR, Nb_Detected, Nb_Corrected, Out); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Check : unable to check the ACR node structure"); + SM_Error_Print (); + + if (Out) fprintf (Out, "%d error(s) could not be corrected in heap \"%s\" which will be declared as corrupted.\n Please contact an administrator about it.\n", *Nb_Detected - *Nb_Corrected, Heap->Name); + Heap->MHH->State = SMD_STATE_CORRUPTED; + + return rc; + } + + /* Vérification de la structure FCR du heap */ + + if (Out) fprintf (Out, "Checking the FCR node structure ...\n"); + + rc = ND_DataStruct_Check (Heap->MHH->FCR, Nb_Detected, Nb_Corrected, Out); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Check : unable to check the ACR node structure"); + SM_Error_Print (); + + if (Out) fprintf (Out, "%d error(s) could not be corrected in heap \"%s\" which will be declared as corrupted.\n Please contact an administrator about it.\n", *Nb_Detected - *Nb_Corrected, Heap->Name); + Heap->MHH->State = SMD_STATE_CORRUPTED; + + return rc; + } + + /* Conclusion de la procédure de vérification */ + + if (*Nb_Detected > *Nb_Corrected) + { + /* On déclare le heap corrompu afin que plus personne n'y accède */ + + if (Out) fprintf (Out, "%d error(s) could not be corrected in heap \"%s\" which will be declared as corrupted.\n Please contact an administrator about it.\n", *Nb_Detected - *Nb_Corrected, Heap->Name); + + Heap->MHH->State = SMD_STATE_CORRUPTED; + + return SMS_KO; + } + + /* On rend le heap valide */ + + if (*Nb_Detected == 0) + { + if (Out) fprintf (Out, "No error detected on heap \"%s\" which will be declared as a valid heap\n", Heap->Name); + } + else + { + if (Out) fprintf (Out, "Every %d error(s) have beeen corrected on heap \"%s\" which will be declared as a valid heap\n", *Nb_Corrected, Heap->Name); + } + + Heap->MHH->State = SMD_STATE_VALID; + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Allocation d'un chunk dans un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Size : taille du chunk */ +/* (O) Ptr : adresse d'un pointeur sur la zone de données allouée */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Chunk_Alloc_I ( SMT_Heap * Heap, size_t Alloc_Size, void ** Ptr ) +{ + NDT_Node * Node; + SMT_Chunk * Chunk; + SMT_DSH * DSH; + int Found; + size_t Round_Size; + SMT_Status rc; + + *Ptr = NULL; + + /* + On invalide le heap jusqu'à ce que la procédure d'allocation soit entièrement terminée. + Ainsi, si celle-ci est interrompue, le heap restera invalide jusqu'à ce qu'il soit + "réparé" (appel de la fonction SM_Heap_Check par la fonction SM_Heap_Open). + */ + + Heap->MHH->State = SMD_STATE_UNVALIDATED; + + /* + Pour le heap système, tous les chunks alloués ont la même taille (DEFAULT_CHUNK_SIZE). + Ceci facilite notamment la récupération des errors (Recovery) dans le heap système. + Ceci a aussi pour but de simplifier (et donc d'optimiser) l'allocation de nouveaux chunks + dans ce heap système dont la mémoire n'a pas besoin d'être optimisée. + + */ + + if (Heap == System_Heap) Alloc_Size = DEFAULT_CHUNK_SIZE; + + /* + Attention : pour les autres heaps, la taille allouée doit être arrondie à un multiple + de 4 octets (en 32 bits) afin que les adresses des chunks soient alignées (sinon SIGBUS !). + */ + + Round_Size = Alloc_Size % sizeof (void *); + + if (Round_Size) Alloc_Size += sizeof (void *) - Round_Size; + + /* Recherche d'un chunk suffisamment grand dans la liste des chunks libres */ + + Found = FALSE; + + ND_Node_First_Get (Heap->MHH->FCR, &Node); + while (Found == FALSE && Node) + { + Chunk = (SMT_Chunk *)(Node->Value); + + if (Chunk->Size >= Alloc_Size) Found = TRUE; + else ND_Node_Next_Get (Node, &Node); + } + + if (Found == FALSE) + { + /* + Si aucun chunk libre suffisamment grand n'a été trouvé, + alors on crée un nouveau segment de données. + */ + + size_t Seg_Size; + + if (Alloc_Size + sizeof (NDT_Node) + sizeof (SMT_Chunk) > Heap->MHH->Segment_Size) + Seg_Size = Alloc_Size + sizeof (NDT_Node) + sizeof (SMT_Chunk); + else + Seg_Size = Heap->MHH->Segment_Size; + + DSH = SM_DataSegment_Init (Heap->MHH, Seg_Size); + if (!DSH) + { + sprintf (SM_Error_Msg, "SM_Chunk_Alloc : unable to create a new data segment for heap \"%s\"", Heap->Name); + SM_Error_Print (); + + return SMS_ERRSHM; + } + + rc = ND_Value_Add (Heap->MHH->DSR, DSH); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Chunk_Alloc : unable to add a data segment to the DSR structure of heap \"%s\"", Heap->Name); + SM_Error_Print (); + + SM_DataSegment_End (Heap->MHH->DSR, DSH); + + return rc; + } + + /* + Maintenant que l'on a ajouté un segment de données, il existe + un chunk libre suffisamment grand au début de ce segment. + */ + + Node = (NDT_Node *)DSH->Start; + Chunk = (SMT_Chunk *)(Node->Value); + } + + /* Suppression du chunk de la liste des chunks libres */ + + rc = ND_Node_Remove (Node); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Chunk_Alloc : unable to remove a chunk from the FCR structure of heap \"%s\"", Heap->Name); + SM_Error_Print (); + + return rc; + } + + /* Ajout du chunk à la liste des chunks alloués */ + + rc = ND_Node_Add (Heap->MHH->ACR, Node); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Chunk_Alloc : unable to add a chunk to the ACR structure of heap \"%s\"", Heap->Name); + SM_Error_Print (); + + /* On tente de revenir en arrière */ + + ND_Node_Add (Heap->MHH->FCR, Node); + + return rc; + } + + /* + Si le chunk trouvé est plus grand que ce dont on a besoin, alors + on peut créer un nouveau chunk libre avec le reliquat de mémoire. + */ + + if (Chunk->Size - Alloc_Size > 0) + { + size_t Remaining_Size = Chunk->Size - Alloc_Size; + + /* + La création d'un nouveau chunk libre requiert de la place pour les + données système (SMT_Chunk + NDT_Node) : on ne crée donc un nouveau + chunk libre que si le reliquat est suffisamment important. + */ + + if (Remaining_Size > sizeof (SMT_Chunk) + sizeof (NDT_Node)) + { + NDT_Node * New_Node; + SMT_Chunk * New_Chunk; + size_t New_Chunk_Size; + + /* Création d'un nouveau chunk libre (noeud puis valeur) juste derrière le chunk trouvé */ + + New_Node = (NDT_Node *)((size_t)(Chunk->Data) + Alloc_Size); + + New_Chunk = (SMT_Chunk *)((size_t)New_Node + sizeof (NDT_Node) ); + + New_Chunk_Size = Remaining_Size - sizeof (SMT_Chunk) - sizeof (NDT_Node); + + New_Chunk->Size = New_Chunk_Size; + + New_Chunk->Data = (void *)((size_t)(New_Chunk) + sizeof (SMT_Chunk) ); + + New_Node->Root = NULL; + New_Node->Parent = NULL; + New_Node->Left = NULL; + New_Node->Right = NULL; + New_Node->Value = New_Chunk; + + rc = ND_Node_Add (Heap->MHH->FCR, New_Node); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Chunk_Alloc : unable to add a chunk to the FCR structure of heap \"%s\"", Heap->Name); + SM_Error_Print (); + + return rc; + } + + /* Ajustement du chunk alloué */ + + Chunk->Size = Alloc_Size; + } + } + + /* + Pour une allocation dans le heap système, on anticipe l'ajout + d'un nouveau segment pour éviter de se retrouver bloqué. + + Bien entendu, cette opération n'est faite que si l'on n'est + pas déjà en train d'étendre le heap système (Adding_Segment=TRUE). + */ + + if (Heap == System_Heap && Adding_Segment == FALSE) + { + SMT_Chunk * Free_Chunk; + unsigned int Free_Usable_Chunk = 0; + size_t Free_Usable_Size = 0; + int New_Seg_Needed = FALSE; + + /* On compte le nombre de chunks libres "utilisables" dans la structure FCR */ + + ND_Node_First_Get (Heap->MHH->FCR, &Node); + while (Node) + { + Free_Chunk = Node->Value; + + if (Free_Chunk->Size >= DEFAULT_CHUNK_SIZE) + { + Free_Usable_Chunk++; + Free_Usable_Size += Free_Chunk->Size; + } + + ND_Node_Next_Get (Node, &Node); + } + + /* + S'il reste au moins FREE_CHUNK_LIMIT chunks libres "utilisables" + ou bien si ces chunks libres "utilisables" représentent suffisament de + place pour allouer FREE_CHUNK_LIMIT nouveaux chunks, alors tout est OK. + + Dans le cas contraire, il est urgent d'étendre le heap système. + */ + + if (Free_Usable_Chunk < FREE_CHUNK_LIMIT) + { + size_t Needed_Size; + + Needed_Size = (size_t)(FREE_CHUNK_LIMIT * DEFAULT_CHUNK_SIZE) + (size_t)(FREE_CHUNK_LIMIT - Free_Usable_Chunk) * (sizeof (NDT_Node) + sizeof (SMT_Chunk)); + + if (Free_Usable_Size < Needed_Size) New_Seg_Needed = TRUE; + } + + if (New_Seg_Needed == TRUE) + { + NDT_Node * New_Node; + + /* + Puisque l'ajout d'un nouveau segment va appeler cette même fonction, + on positionne une variable globale pour ne pas recommencer cette opération. + */ + + Adding_Segment = TRUE; + + /* + On alloue le noeud du nouveau segment avant de faire appel à la fonction + SM_DataSegment_Init pour éviter que ce noeud soit alloué dans le nouveau segment. + */ + + SM_System_Alloc (sizeof (NDT_Node), (void **)(&New_Node), NULL); + New_Node->Root = NULL; + New_Node->Parent = NULL; + New_Node->Left = NULL; + New_Node->Right = NULL; + + /* On crée le nouveau segment */ + + DSH = SM_DataSegment_Init (Heap->MHH, Heap->MHH->Segment_Size); + if (!DSH) + { + sprintf (SM_Error_Msg, "SM_Chunk_Alloc : unable to create un new data segment for the system heap (anticipation)"); + SM_Error_Print (); + + return SMS_ERRSHM; + } + + New_Node->Value = DSH; + + /* On ajoute le nouveau segment au heap système */ + + rc = ND_Node_Add (Heap->MHH->DSR, New_Node); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Chunk_Alloc : unable to add a data segment to the DSR structure of the system heap (anticipation)"); + SM_Error_Print (); + + SM_DataSegment_End (Heap->MHH->DSR, DSH); + + return rc; + } + + Adding_Segment = FALSE; + } + } + + /* + Puisque la procédure d'allocation d'un chunk s'est correctement + terminée, on peut rendre le heap à nouveau valide. + */ + + Heap->MHH->State = SMD_STATE_VALID; + + *Ptr = Chunk->Data; + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Désallocation d'un chunk */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Ptr : pointeur sur la zone de données du chunk à désallouer */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Chunk_Free_I ( SMT_Heap * Heap, void * Ptr) +{ + NDT_Node * Node; + SMT_Chunk * Chunk; + SMT_Status rc; + + /* + On invalide le heap jusqu'à ce que la procédure de désallocation soit entièrement terminée. + Ainsi, si celle-ci est interrompue, le heap restera invalide jusqu'à ce qu'il soit + "réparé" (appel de la fonction SM_Heap_Check par la fonction SM_Heap_Open). + */ + + Heap->MHH->State = SMD_STATE_UNVALIDATED; + + /* + Le noeud du chunk étant adjoint à celui-ci, on n'a pas besoin + de le rechercher dans la liste des chunks alloués. + */ + + Node = (NDT_Node *)((size_t)Ptr - sizeof (SMT_Chunk) - sizeof (NDT_Node)); + + Chunk = Node->Value; + + /* Suppression du chunk de la liste des chunks alloués */ + + rc = ND_Node_Remove (Node); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Chunk_Free : unable to remove the allocated chunk from the ACR structure of heap \"%s\"", Heap->Name); + SM_Error_Print (); + + return rc; + } + + /* Ajout du chunk à la liste des chunks libres */ + + rc = ND_Node_Add (Heap->MHH->FCR, Node); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Chunk_Free : unable to add the free chunk to the FCR structure of heap \"%s\"", Heap->Name); + SM_Error_Print (); + + /* Retour arrière */ + + ND_Node_Add (Heap->MHH->ACR, Node); + + return rc; + } + + /* + Puisque la procédure de désallocation d'un chunk s'est correctement + terminé, on peut rendre le heap à nouveau valide. + */ + + Heap->MHH->State = SMD_STATE_VALID; + + /* Activation de la compression automatique */ + + if (Heap->MHH->Auto_Compress != SMD_NO_AUTO_COMPRESS && + Heap->MHH->FCR->Node_Number > Heap->MHH->Auto_Compress) + { + size_t Compress_Size; + + rc = SM_Heap_Compress (Heap, &Compress_Size); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Chunk_Free : unable to compress FCR structure of heap \"%s\" which contains %ld free chunks", Heap->Name, Heap->MHH->FCR->Node_Number); + SM_Error_Print (); + return rc; + } + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* FONCTIONS SECURISEES (SM_MODE = 0) */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Ouverture d'une instance de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Instance : instance de la librairie */ +/* (I) Context : nom du nouveau contexte */ +/* (I) Open_Mode : indicateur création/ouverture + mode d'affichage des erreurs */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Open_C ( int Instance, const char * Context, SMT_Flags Open_Mode ) +{ + return SM_Library_Open_I (Instance, Context, Open_Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du numéro de l'instance utilisée */ +/*------------------------------------------------------------------------------*/ +/* (O) Instance : adresse du numéro de l'instance utilisée */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Instance_Get_C ( int * Instance ) +{ + return SM_Library_Instance_Get_I (Instance); +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du nom du contexte utilisé */ +/*------------------------------------------------------------------------------*/ +/* (O) Context : adresse du nom du contexte utilisé */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Context_Get_C ( char ** Context ) +{ + return SM_Library_Context_Get_I (Context); +} + +/*------------------------------------------------------------------------------*/ +/* Changement de contexte d'utilisation de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Context : nom du nouveau contexte */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Context_Set_C ( const char * Context ) +{ + return SM_Library_Context_Set_I (Context); +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture de l'instance de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Close_Mode : mode de fermeture (destruction ou fermeture simple) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Close_C ( SMT_Flags Close_Mode ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Library_Close : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + return SM_Library_Close_I (Close_Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Affichage des informations de la base de mémoires partagées */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Dump_C (FILE * Out) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Library_Dump : the LIBSHMEM library is not open"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Library_Dump_I (Out); +} + +/*------------------------------------------------------------------------------*/ +/* Libération de tous les verrous (base, heap) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Unlock_C ( void ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Library_Unlock : the LIBSHMEM library is not open"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Library_Unlock_I (); +} + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Library_Stderr_Set_C ( FILE * Out ) +{ + return SM_Library_Stderr_Set_I (Out); +} + +/*------------------------------------------------------------------------------*/ +/* Test d'existence d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap_Name : Nom du heap */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Exist_C ( const char * Heap_Name ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Heap_Exist : the LIBSHMEM library is not open"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + if (!Heap_Name) + { + sprintf (SM_Error_Msg, "SM_Heap_Exist : the heap name is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Heap_Exist_I (Heap_Name); +} + +/*------------------------------------------------------------------------------*/ +/* Ouverture/création d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap_Name : nom du heap */ +/* (O) Heap : pointeur sur le heap ouvert / créé */ +/* (I) Seg_Size : taille des segments du heap */ +/* (I) Open_Mode : mode d'ouverture du heap */ +/* (O) Locked : verrou effectif (TRUE ou FALSE) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Open_C ( const char * Heap_Name, SMT_Heap ** Heap, size_t Seg_Size, SMT_Flags Open_Mode, int * Locked ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap_Name) + { + sprintf (SM_Error_Msg, "SM_Heap_Open : the heap name is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Heap_Open_I (Heap_Name, Heap, Seg_Size, Open_Mode, Locked); +} + +/*------------------------------------------------------------------------------*/ +/* Teste si un heap a déjà été ouvert par le processus courant */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap_Name : Nom du heap */ +/* (O) Heap : pointeur sur le heap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_IsOpen_C ( const char * Heap_Name, SMT_Heap ** Heap ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Heap_IsOpen : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap_Name) + { + sprintf (SM_Error_Msg, "SM_Heap_IsOpen : the heap name is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Heap_IsOpen_I (Heap_Name, Heap); +} + +/*------------------------------------------------------------------------------*/ +/* Destruction d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_End_C ( const char * Heap_Name ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Heap_End : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap_Name) + { + sprintf (SM_Error_Msg, "SM_Heap_End : the heap name is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Heap_End_I (Heap_Name); +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Close_C ( SMT_Heap * Heap ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Heap_Close : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap) + { + sprintf (SM_Error_Msg, "SM_Heap_Close : the heap is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Heap_Close_I (Heap); +} + +/*------------------------------------------------------------------------------*/ +/* Pose d'un verrou sur un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Lock_Mode : mode de verrouillage (SMD_READ ou SMD_WRITE) */ +/* (O) Locked : verrouillage effectué (TRUE ou FALSE) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Lock_C ( SMT_Heap * Heap, SMT_Flags Lock_Mode, int * Locked ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock : the heap is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Heap_Lock_I (Heap, Lock_Mode, Locked); +} + +/*------------------------------------------------------------------------------*/ +/* Libération d'un verrou sur un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur unheap ouvert */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Unlock_C ( SMT_Heap * Heap ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Heap_Unlock : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap) + { + sprintf (SM_Error_Msg, "SM_Heap_Unlock : the heap is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Heap_Unlock_I (Heap); +} + +/*------------------------------------------------------------------------------*/ +/* Configuration d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Tag : type de configuration */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Config_C ( SMT_Heap * Heap, SMT_Config Tag, ... ) +{ + va_list Arguments; + size_t Segment_Size, Limit_Size, Current_Size; + SMT_Status rc; + + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Heap_Config : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap) + { + sprintf (SM_Error_Msg, "SM_Heap_Config : the heap is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + va_start (Arguments, Tag); + + switch (Tag) + { + case SMD_SEGMENT_SIZE: + + Segment_Size = va_arg (Arguments, size_t); + Heap->MHH->Segment_Size = Segment_Size; + + break; + + case SMD_HEAP_LIMIT: + + Limit_Size = va_arg (Arguments, size_t); + Current_Size = 0; + + if (Limit_Size != SMD_UNLIMITED) + { + /* On contrôle que la limite fixée est inférieure à la taille actuelle du heap */ + + rc = ND_DataStruct_Traverse (Heap->MHH->DSR, NDD_CMD_SUM_VALUES, (void *)&Current_Size); + if (rc != NDS_OK) return rc; + + if (Current_Size > Limit_Size) + { + sprintf (SM_Error_Msg, "SM_Heap_Config : the heap has already exceeded the limit size (%d bytes)", Current_Size); + SM_Error_Print (); + + va_end (Arguments); + return SMS_ERRAPI; + } + } + + Heap->MHH->Limit_Size = Limit_Size; + + break; + + default : + sprintf (SM_Error_Msg, "SM_Heap_Config : unknown config tag %d", Tag); + SM_Error_Print (); + + va_end (Arguments); + return SMS_ERRAPI; + } + + va_end (Arguments); + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Compression d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (O) Compress : pointeur sur la taille mémoire gagnée */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Compress_C ( SMT_Heap * Heap, size_t * Compress ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Heap_Compress : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap) + { + sprintf (SM_Error_Msg, "SM_Heap_Compress : the heap is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + if (!Compress) + { + sprintf (SM_Error_Msg, "SM_Heap_Compress : the compress size pointer is null"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Heap_Compress_I (Heap, Compress); +} + +/*------------------------------------------------------------------------------*/ +/* Vérification/correction des structures d'un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (O) Nb_Detected : pointeur sur le nombre d'erreurs détectées */ +/* (O) Nb_Corrected : pointeur sur le nombre d'erreurs corrigées */ +/* (I) Out : pointeur sur le flux de sortie du rapport */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Check_C ( SMT_Heap * Heap, int * Nb_Detected, int * Nb_Corrected, FILE * Out ) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Heap_Check : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap) + { + sprintf (SM_Error_Msg, "SM_Heap_Check : the heap is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + if (!Nb_Detected || !Nb_Corrected) + { + sprintf (SM_Error_Msg, "SM_Heap_Check : the error number pointer is null"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + if (!Out) + { + sprintf (SM_Error_Msg, "SM_Heap_Check : the out stream is null"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Heap_Check_I (Heap, Nb_Detected, Nb_Corrected, Out); +} + +/*------------------------------------------------------------------------------*/ +/* Allocation d'un chunk dans un heap */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Size : taille du chunk */ +/* (O) Ptr : adresse d'un pointeur sur la zone de données allouée */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Chunk_Alloc_C ( SMT_Heap * Heap, size_t Alloc_Size, void ** Ptr) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Chunk_Alloc : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap) + { + sprintf (SM_Error_Msg, "SM_Chunk_Alloc : the heap is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + if (!Ptr) + { + sprintf (SM_Error_Msg, "SM_Chunk_Alloc : the chunk address is null"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Chunk_Alloc_I (Heap, Alloc_Size, Ptr); +} + +/*------------------------------------------------------------------------------*/ +/* Désallocation d'un chunk */ +/*------------------------------------------------------------------------------*/ +/* (I) Heap : pointeur sur un heap ouvert */ +/* (I) Ptr : pointeur sur la zone de données du chunk à désallouer */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Chunk_Free_C ( SMT_Heap * Heap, void * Ptr) +{ + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Chunk_Free : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + if (!Heap) + { + sprintf (SM_Error_Msg, "SM_Chunk_Free : the heap is undefined"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + if (!Ptr) + { + sprintf (SM_Error_Msg, "SM_Chunk_Free : the chunk pointer is null"); + SM_Error_Print (); + return SMS_ERRAPI; + } + + return SM_Chunk_Free_I (Heap, Ptr); +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* FONCTIONS PRIVEES */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Allocation de mémoire dans la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Alloc (size_t Size, void ** Ptr, void * Data) +{ + *Ptr = NULL; + + *Ptr = SM_Base->Free; + SM_Base->Free = (void *)((size_t)(SM_Base->Free) + Size); + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Désallocation de mémoire dans la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Free (void * Ptr, void * Data) +{ + if (!Ptr) return SMS_ERRAPI; + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Allocation de mémoire dans le heap système */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_System_Alloc (size_t Size, void ** Ptr, void * Data) +{ + return SM_Chunk_Alloc_I (System_Heap, Size, Ptr); +} + +/*------------------------------------------------------------------------------*/ +/* Désallocation de mémoire dans le heap système */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_System_Free (void * Ptr, void * Data) +{ + return SM_Chunk_Free_I (System_Heap, Ptr); +} + +/*------------------------------------------------------------------------------*/ +/* Initialisation de la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Init ( void ) +{ + SMT_Status rc; + int SemID; + int SysMemID; + int DataMemID; + union semun Sem_Ctl; + size_t Size; + int Locked; + + /* Création du sémaphore pour la gestion des verrous sur la base */ + + SemID = semget (IPC_PRIVATE, 1, 0777|IPC_CREAT|IPC_EXCL); + if (SemID == -1) + { + switch (errno) + { + case ENOMEM: + sprintf (SM_Error_Msg, "SM_Base_Init : the amount of memory is not sufficient to create a new semaphore"); + break; + + case ENOSPC: + sprintf (SM_Error_Msg, "SM_Base_Init : the number of semaphores exceeds the system-imposed limit"); + break; + + default : + sprintf (SM_Error_Msg, "SM_Base_Init : unknown error (%d) while creating a semaphore", errno); + break; + } + + SM_Error_Print (); + + return SMS_ERRSEM; + } + + /* Initialisation du sémaphore à 1 (aucun verrou) */ + + Sem_Ctl.val = 1; + + if (semctl (SemID, 0, SETVAL, Sem_Ctl )) + { + sprintf (SM_Error_Msg, "SM_Base_Init : unable to initialize the value of semaphore %d", SemID); + SM_Error_Print (); + + rc = SMS_ERRSEM; + goto Error1; + } + + /* + Création d'un segment de mémoire partagée qui contiendra la structure SMT_Base. + Ce segment peut être attaché à n'importe quelle adresse. + */ + + SysMemID = shmget (SM_Instance, (int) sizeof (SMT_Base), 0777|IPC_CREAT|IPC_EXCL); + if (SysMemID == -1) + { + switch (errno) + { + case EEXIST: + sprintf (SM_Error_Msg, "SM_Base_Init : the shared memory segment identifier %d already exists", SM_Instance); + break; + + case EINVAL: + sprintf (SM_Error_Msg, "SM_Base_Init : the size of the shared memory segment (%d) is out of the system-imposed bounds", sizeof (SMT_Base)); + break; + + case ENOMEM: + sprintf (SM_Error_Msg, "SM_Base_Init : the amount of memory is not sufficient to create the shared memory segment"); + break; + + case ENOSPC: + sprintf (SM_Error_Msg, "SM_Base_Init : the number of shared memory segments exceeds the system-imposed limit"); + break; + + default : + sprintf (SM_Error_Msg, "SM_Base_Init : unknown error (%d) while creating the shared memory segment", errno); + break; + } + + SM_Error_Print (); + + rc = SMS_ERRSHM; + goto Error1; + } + + /* On attache le segment de mémoire partagée au processus courant */ + + errno = 0; + SM_Base = shmat (SysMemID, 0, 0); + if (errno) + { + sprintf (SM_Error_Msg, "SM_Base_Init : unable to attach the first shared memory segment to the current process (error %d)", errno); + SM_Error_Print (); + + rc = SMS_ERRSHM; + goto Error2; + } + + /* + Attention : tant que le heap système n'est pas créé, on est obligé d'allouer de + la mémoire dans le segment de mémoire partagée de la base (fonction SM_Base_Alloc). + + Les ressources à allouer (structure MHR + ressources du heap système) sont référencées + par des pointeurs et doivent par conséquent être contenues dans un segment attaché à + une adresse commune à tous les processus. + On crée donc ce segment de mémoire partagé spécifique dont l'adresse d'attachement + sera mémorisée dans la structure SMT_Base. + + Pour ce segment de mémoire partagé, on réserve de la place pour : + - la structure du MHR (NDT_Root) + - les ressources du heap système, i.e : + - son noeud (NDT_Node) + - sa structure d'entête ( SMT_MHH) + - sa structure DSR (NDT_Root) + - sa structure ACR (NDT_Root) + - sa structure FCR (NDT_Root) + - son premier segment de données (noeud + entête) + */ + + Size = sizeof (NDT_Root) + sizeof (NDT_Node) + sizeof (SMT_MHH) + 3 * sizeof (NDT_Root) + sizeof (NDT_Node) + sizeof (SMT_DSH); + + DataMemID = shmget (IPC_PRIVATE, Size, 0777|IPC_CREAT|IPC_EXCL); + if (DataMemID == -1) + { + switch (errno) + { + case EINVAL: + sprintf (SM_Error_Msg, "SM_Base_Init : the size of the shared memory segment (%d) is out of the system-imposed bounds", Size); + break; + + case ENOMEM: + sprintf (SM_Error_Msg, "SM_Base_Init : the amount of memory is not sufficient to create the shared memory segment"); + break; + + case ENOSPC: + sprintf (SM_Error_Msg, "SM_Base_Init : the number of shared memory segments exceeds the system-imposed limit"); + break; + + default : + sprintf (SM_Error_Msg, "SM_Base_Init : unknown error (%d) while creating a shared memory segment", errno); + break; + } + + SM_Error_Print (); + + rc = SMS_ERRSHM; + goto Error3; + } + + /* Initialisation des informations rattachées à la base */ + + SM_Base->SemID = SemID; + SM_Base->SysMemID = SysMemID; + SM_Base->DataMemID = DataMemID; + SM_Base->Size = Size; + SM_Base->Creator = getpid (); + SM_Base->Writer = SM_Base->Creator; + SM_Base->Attach = (void *)MEM_LIMIT; + SM_Base->MHR = NULL; + + /* + On attache le segment de mémoire partagée au processus courant + à une adresse la plus haute possible (MEM_LIMIT) afin d'éviter + de déborder sur la plage d'adressage des symboles. + */ + + errno = 0; + SM_Base->Free = shmat (DataMemID, (void *)((size_t)(SM_Base->Attach) - Size), SHM_RND); + if (errno) + { + sprintf (SM_Error_Msg, "SM_Base_Init : unable to attach the second shared memory segment to the current process (error %d)", errno); + SM_Error_Print (); + + rc = SMS_ERRSHM; + goto Error4; + } + + SM_Base->Attach = SM_Base->Free; + + /* Création du MHR dans la base */ + + rc = ND_DataStruct_Open (&(SM_Base->MHR), NDD_DS_LIST | NDD_MN_FIFO, "SM_Base_Alloc", "SM_Base_Free", NULL, TRUE); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_Init : unable to create the MHR structure"); + SM_Error_Print (); + + goto Error4; + } + + strcpy (SM_Base->MHR->Manager, "MHR_Manager"); + + /* + Création d'un premier heap qui constituera le heap système + (l'allocation du MHN, du MHH et des structures DSR, ACR et FCR + sont effectuées dans la base) + */ + + rc = SM_Heap_Open_I (HEAP_SYSTEM, &System_Heap, 0, SMD_CREATE, &Locked); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_Init : unable to create the system heap"); + SM_Error_Print (); + + goto Error5; + } + + /* + On change les fonctions d'allocation et de désallocation du MHR afin que désormais, + les allocations des nouveaux heaps soient faites dans le heap système. + */ + + strcpy (SM_Base->MHR->Allocator, "SM_System_Alloc"); + strcpy (SM_Base->MHR->Desallocator, "SM_System_Free"); + + /* + On change les fonctions Allocator et Desallocator du DSR, ACR + et FCR du heap système afin que désormais, les allocations des + nouveaux segments et chunks soient faites dans le segment de + données du heap système. + */ + + strcpy (System_Heap->MHH->DSR->Allocator, "SM_System_Alloc"); + strcpy (System_Heap->MHH->DSR->Desallocator, "SM_System_Free"); + strcpy (System_Heap->MHH->ACR->Allocator, "SM_System_Alloc"); + strcpy (System_Heap->MHH->ACR->Desallocator, "SM_System_Free"); + strcpy (System_Heap->MHH->FCR->Allocator, "SM_System_Alloc"); + strcpy (System_Heap->MHH->FCR->Desallocator, "SM_System_Free"); + + /* Verrouillage de la base en lecture */ + + rc = SM_Base_Lock (SMD_READ); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_Init : unable to lock the shared memory base for reading"); + SM_Error_Print (); + + goto Error5; + } + + return SMS_OK; + + /* Gestion d'erreur */ + + Error5: + ND_DataStruct_Close (SM_Base->MHR); + Error4: + shmdt ((void *)(SM_Base->Free)); + Error3: + shmctl (DataMemID, IPC_RMID, 0); + Error2: + shmdt ((void *)SM_Base); + shmctl (SysMemID, IPC_RMID, 0); + SM_Base = NULL; + Error1: + semctl (SemID, 0, IPC_RMID, Sem_Ctl); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Destruction de la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_End ( void ) +{ + int SemID; + int SysMemID, DataMemID; + SMT_Status rc; + union semun Sem_Ctl; + NDT_Node * Node, * Previous_Node; + + /* Retrait du verrou en lecture sur la base */ + + rc = SM_Base_Unlock (SMD_READ); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_End : unable to unlock the shared memory base"); + SM_Error_Print (); + + return rc; + } + + /* Verrouillage de la base en écriture */ + + rc = SM_Base_Lock (SMD_WRITE); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_End : unable to lock the shared memory base for writing"); + SM_Error_Print (); + + SM_Base_Lock (SMD_READ); + + return rc; + } + + /* + Destruction de tous les heaps (parcours du MHR en + sens inverse pour détruire le heap système en dernier). + + NB : à chaque destruction de heap, la base est verrouillée en écriture + */ + + ND_Node_Last_Get (SM_Base->MHR, &Node); + + while (Node) + { + SMT_MHH * MHH = (SMT_MHH *)(Node->Value); + + ND_Node_Previous_Get (Node, &Previous_Node); + + /* + Pour la suppression du heap système, il faut redéfinir la fonction de + désallocation du MHR, car il a été alloué dans la base (voir SM_Base_Init) + */ + + if (!Previous_Node) strcpy (SM_Base->MHR->Desallocator, "SM_Base_Free"); + + /* Retrait du heap de la structure du MHR */ + + rc = ND_Value_Remove (SM_Base->MHR, MHH, (void **)&MHH); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_End : unable to remove heap \"%s\" from the MHR", MHH->Name); + SM_Error_Print (); + + SM_Base_Unlock (SMD_WRITE); + SM_Base_Lock (SMD_READ); + + return rc; + } + + /* Suppression du heap */ + + rc = ND_Value_Free (SM_Base->MHR, MHH); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_End : unable to free heap \"%s\"", MHH->Name); + SM_Error_Print (); + + SM_Base_Unlock (SMD_WRITE); + SM_Base_Lock (SMD_READ); + + return rc; + } + + Node = Previous_Node; + } + + SemID = SM_Base->SemID; + SysMemID = SM_Base->SysMemID; + DataMemID = SM_Base->DataMemID; + + /* Destruction des segments de mémoire partagée de la base */ + + if (shmctl (DataMemID, IPC_RMID, 0) == -1 || shmctl (SysMemID, IPC_RMID, 0) == -1) + { + switch (errno) + { + case EPERM: + sprintf (SM_Error_Msg, "SM_Base_End : current process (%d) is not allowed to destroy the shared memory segment %d or %d", (int)getpid (), SysMemID, DataMemID); + break; + + case EINVAL: + sprintf (SM_Error_Msg, "SM_Base_End : no shared memory segment exists for identifier %d or %d", SysMemID, DataMemID); + break; + + default : + sprintf (SM_Error_Msg, "SM_Base_End : unknown error (%d) while destroying the shared memory segment %d or %d", errno, SysMemID, DataMemID); + break; + } + + SM_Error_Print (); + + SM_Base = NULL; + + return SMS_ERRSHM; + + } + + SM_Base = NULL; + + /* Destruction du sémaphore de gestion des verrous sur la base */ + + if (semctl (SemID, 0, IPC_RMID, Sem_Ctl) == -1) + { + switch (errno) + { + case EPERM: + sprintf (SM_Error_Msg, "SM_Base_End : current process (%d) is not allowed to destroy semaphore %d", (int)getpid (), SemID); + break; + + case EINVAL: + sprintf (SM_Error_Msg, "SM_Base_End : no semaphore corresponds to the identifier %d", SemID); + break; + + default : + sprintf (SM_Error_Msg, "SM_Base_End : unknown error (%d) while destroying semaphore %d", errno, SemID); + break; + } + + SM_Error_Print (); + + return SMS_ERRSEM; + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ouverture de la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Open ( void ) +{ + SMT_Status rc; + void * Ptr; + int MemID; + int Locked; + + if (SM_Base) return SMS_OK; + + /* Récupération de l'identifiant du segment de mémoire partagée de la base */ + + MemID = shmget (SM_Instance, 0, 0); + if (MemID == -1) + { + switch (errno) + { + case EACCES: + sprintf (SM_Error_Msg, "SM_Base_Open : the shared memory segment %d is not accessible to the current process", SM_Instance); + break; + + case EIDRM: + sprintf (SM_Error_Msg, "SM_Base_Open : the shared memory segment %d has been deleted", SM_Instance); + break; + + case ENOENT: + sprintf (SM_Error_Msg, "SM_Base_Open : no shared memory segment corresponds to the identifier %d", SM_Instance); + break; + + default : + sprintf (SM_Error_Msg, "SM_Base_Open : unknown error %d while retrieving a shared memory segment", errno); + break; + } + + SM_Error_Print (); + + return SMS_ERRSHM; + } + + /* On attache les segments de mémoire partagée de la base */ + + errno = 0; + SM_Base = shmat (MemID, 0, 0); + if (errno) + { + sprintf (SM_Error_Msg, "SM_Base_Open : unable to attach the shared memory segment to the current process (error %d)", errno); + SM_Error_Print (); + + SM_Base = NULL; + + return SMS_ERRSHM; + } + + errno = 0; + Ptr = shmat (SM_Base->DataMemID, SM_Base->MHR, 0); + if (errno) + { + sprintf (SM_Error_Msg, "SM_Base_Open : unable to attach the shared memory segment to the current process at the specified address %p (error %d)", SM_Base->MHR, errno); + SM_Error_Print (); + + shmdt ((void *)SM_Base); + SM_Base = NULL; + + return SMS_ERRSHM; + } + + /* Verrouillage de la base en lecture */ + + rc = SM_Base_Lock (SMD_READ); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_Open : unable to lock the shared memory base for reading"); + SM_Error_Print (); + + shmdt ((void *)SM_Base); + SM_Base = NULL; + + return rc; + } + + /* Ouverture du heap système (sans le verrouiller) */ + + rc = SM_Heap_Open_I (HEAP_SYSTEM, &System_Heap, 0, SMD_OPEN, &Locked); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_Open : unable to open the system heap"); + SM_Error_Print (); + + shmdt ((void *)SM_Base); + SM_Base = NULL; + + return rc; + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture de la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Close ( void ) +{ + NDT_Node * Node; + + if (!SM_Base) + { + sprintf (SM_Error_Msg, "SM_Base_Close : the LIBSHMEM library is not open"); + SM_Error_Print (); + + return SMS_ERRAPI; + } + + /* + Fermeture de tous les heaps (sans déverrouillage) ouverts. + + Attention : il faut fermer le heap système en dernier. + */ + + ND_Node_First_Get (Opened_Heap_List, &Node); + + while (Node) + { + NDT_Node *Next_Node; + ND_Node_Next_Get (Node, &Next_Node); + SM_Heap_Close_I ((SMT_Heap *)(Node->Value)); + Node = Next_Node;; + } + + /* Déverrouillage de la base en lecture */ + + SM_Base_Unlock (SMD_READ); + + /* Détachement des segments de mémoire partagée de la base */ + + shmdt ((void *)SM_Base->MHR); + shmdt ((void *)SM_Base); + + SM_Base = NULL; + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Pose d'un verrou sur la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Lock ( SMT_Flags Lock_Mode ) +{ + SMT_Status rc; + + if (Lock_Mode & SMD_READ) + { + rc = SM_Semaphore_Operate (SM_Base->SemID, SM_SemOp_SSL, 2); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_Lock : unable to lock the library base for reading"); + SM_Error_Print (); + + return rc; + } + } + + if (Lock_Mode & SMD_WRITE) + { + rc = SM_Semaphore_Operate (SM_Base->SemID, SM_SemOp_SEL, 2); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_Lock : unable to lock the library base for writing"); + SM_Error_Print (); + + return rc; + } + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Libération d'un verrou sur la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Unlock ( SMT_Flags Lock_Mode ) +{ + SMT_Status rc; + + if (Lock_Mode & SMD_READ) + { + rc = SM_Semaphore_Operate (SM_Base->SemID, SM_SemOp_RSL, 2); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_Unlock : unable to unlock the library base which had been locked for reading"); + SM_Error_Print (); + + return rc; + } + } + + if (Lock_Mode & SMD_WRITE) + { + rc = SM_Semaphore_Operate (SM_Base->SemID, SM_SemOp_REL, 2); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Base_Unlock : unable to unlock the library base which had been locked for writing"); + SM_Error_Print (); + + return rc; + } + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fonction manager de la liste des heaps ouverts */ +/*------------------------------------------------------------------------------*/ +NDT_Status SM_Opened_Heap_List_Manager (va_list Args) +{ + NDT_Command Command = (NDT_Command)va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_COMP_VALUE) + { + SMT_Heap * Heap1, * Heap2; + long comp; + + Heap1 = (SMT_Heap *)va_arg (Args, void *); + Heap2 = (SMT_Heap *)va_arg (Args, void *); + + va_end (Args); + + comp = strcmp (Heap1->Name, Heap2->Name); + + if (comp < 0) return NDS_LOWER; + + if (comp > 0) return NDS_GREATER; + + return NDS_EQUAL; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + SMT_Heap * Heap = (SMT_Heap *) va_arg (Args, void *); + + free (Heap->Name); + free (Heap); + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fonction manager du MHR (Memory Heap Root) */ +/*------------------------------------------------------------------------------*/ +NDT_Status MHR_Manager (va_list Args) +{ + SMT_Status rc; + NDT_Command Command = (NDT_Command)va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_PRINT_VALUE) + { + SMT_MHH * MHH = (SMT_MHH *)va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + size_t Segment_Size; + size_t Alloc_Size; + size_t Free_Size; + int Nb_Segment; + int Nb_Alloc_Chunk; + int Nb_Free_Chunk; + SMT_Heap * Heap; + int Locked; + char * ptr; + + /* On n'affiche le heap que s'il fait partie du contexte courant */ + + ptr = strstr (MHH->Name, SM_Context); + if (ptr) ptr += strlen (SM_Context) + 1; + else if (!strcmp (HEAP_SYSTEM, MHH->Name)) ptr = MHH->Name; + else return SMS_KO; + + if (MHH->State == SMD_STATE_CORRUPTED) + { + fprintf (Out, "Heap \"%s\" : *** CORRUPTED *** (checked by process %ld)", MHH->Name, MHH->Writer); + + return NDS_OK; + } + + rc = SM_Heap_Open_I (ptr, &Heap, 0, SMD_OPEN | SMD_READ, &Locked); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "Error MHR_Manager : unable to open heap \"%s\" for reading", MHH->Name); + SM_Error_Print (); + + return rc; + } + + Nb_Segment = MHH->DSR->Node_Number; + ND_DataStruct_Traverse (MHH->DSR, NDD_CMD_SUM_VALUES, (void *)&Segment_Size); + + Nb_Alloc_Chunk = MHH->ACR->Node_Number; + ND_DataStruct_Traverse (MHH->ACR, NDD_CMD_SUM_VALUES, (void *)&Alloc_Size); + + Nb_Free_Chunk = MHH->FCR->Node_Number; + ND_DataStruct_Traverse (MHH->FCR, NDD_CMD_SUM_VALUES, (void *)&Free_Size); + + fprintf (Out, "Heap \"%s\" :\n\t- Last write access pid = %ld\n\t- ID Sem = %d\n\t- Status = %s\n\t- Data = %d segment(s) - %d bytes\n\t- Allocated = %d chunk(s) - %d bytes\n\t- Free = %d chunk(s) - %d bytes", + ptr, MHH->Writer, MHH->SemID, SM_Lock_Status_Get ("heap", MHH), Nb_Segment, Segment_Size, Nb_Alloc_Chunk, Alloc_Size, Nb_Free_Chunk, Free_Size); + + if (Locked == TRUE) SM_Heap_Unlock_I (Heap); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, SM_Root_Description_Get ("Memory Heap Root", Root)); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + SMT_MHH * MHH1, * MHH2; + long comp; + + MHH1 = (SMT_MHH *)va_arg (Args, void *); + MHH2 = (SMT_MHH *)va_arg (Args, void *); + + va_end (Args); + + comp = strcmp (MHH1->Name, MHH2->Name); + + if (comp < 0)return NDS_LOWER; + + if (comp > 0) return NDS_GREATER; + + return NDS_EQUAL; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + SMT_MHH * MHH = (SMT_MHH *)va_arg (Args, void *); + + return SM_MHH_End (MHH); + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Destruction d'un MHH (Memory Heap Header) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_MHH_End ( SMT_MHH * MHH) +{ + SMT_Status rc; + SMT_Heap To_Find; + union semun Sem_Ctl; + SMT_Heap * Opened_Heap; + + /* Destruction de la structure DSR (et de toutes ses valeurs) */ + + if (!strcmp (MHH->Name, HEAP_SYSTEM)) + { + NDT_Node * Node, * Previous_Node; + SMT_DSH * DSH; + + /* + Pour le heap système, on doit procéder de manière spécifique + car le premier segment contient des références sur les autres + segments. Il faut donc supprimer celui-ci en dernier. + + Par ailleurs, ce premier segment a été alloué dans la base. + Il faudra donc aussi redéfinir la fonction de désallocation + du DSR pour celui-ci. + */ + + ND_Node_Last_Get (MHH->DSR, &Node); + + while (Node) + { + DSH = (SMT_DSH *)(Node->Value); + + ND_Node_Previous_Get (Node, &Previous_Node); + + /* S'agit-il du heap système ? */ + + if (!Previous_Node) strcpy (MHH->DSR->Desallocator, "SM_Base_Free"); + + /* Retrait du segment du DSR */ + + rc = ND_Value_Remove (MHH->DSR, DSH, (void **)&DSH); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_MHH_End : unable to remove the shared memory segment (address=%p) from the DSR structure", DSH->Start); + SM_Error_Print (); + + if (SM_ERROR(rc)) return rc; + } + + /* Destruction du segment */ + + rc = ND_Value_Free (MHH->DSR, DSH); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_MHH_End : unable to free the shared memory segment (address=%p)", DSH->Start); + SM_Error_Print (); + + if (SM_ERROR(rc)) return rc; + } + + Node = Previous_Node; + } + } + else + { + rc = ND_DataStruct_Close (MHH->DSR); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_MHH_End : unable to destroy the DSR structure of heap \"%s\"", MHH->Name); + SM_Error_Print (); + } + } + + /* + Destruction des structures ACR et FCR. + + NB : puisque tous les chunks réfénrencés par les ACR et FCR étaient alloués + dans les segments qui viennent d'être supprimés, on se contente de détuire + leur racine. + */ + + rc = ND_Desallocator_Exec (SM_Base->MHR->Desallocator, MHH->ACR, NULL); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_MHH_End : unable to free the ACR root of heap \"%s\"", MHH->Name); + SM_Error_Print (); + } + + rc = ND_Desallocator_Exec (SM_Base->MHR->Desallocator, MHH->FCR, NULL); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_MHH_End : unable to free the FCR root of heap \"%s\"", MHH->Name); + SM_Error_Print (); + } + + /* Suppression du heap de la liste des heaps ouverts */ + + To_Find.Name = MHH->Name; + rc = ND_Value_Remove (Opened_Heap_List, &To_Find, (void **)&Opened_Heap); + if (rc == NDS_OK) + { + rc = ND_Value_Free (Opened_Heap_List, Opened_Heap); + if (rc != NDS_OK) return rc; + } + + /* Destruction du sémaphore attaché au heap */ + + semctl (MHH->SemID, 0, IPC_RMID, Sem_Ctl); + + /* Désallocation de la structure du MHH */ + + rc = ND_Desallocator_Exec (SM_Base->MHR->Desallocator, MHH, NULL); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_MHH_End : unable to free the header of heap \"%s\"", MHH->Name); + SM_Error_Print (); + } + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* Gestion des segments de données */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Fonction manager pour un DSR (Data Segment Root) */ +/*------------------------------------------------------------------------------*/ +NDT_Status SM_DSR_Manager (va_list Args) +{ + NDT_Command Command = (NDT_Command)va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_SUM_VALUES) + { + SMT_DSH * DSH = (SMT_DSH *)va_arg (Args, void *); + int * Total_Size = (int *)va_arg (Args, int *); + + (*Total_Size) += DSH->Size; + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + SMT_DSH * DSH = (SMT_DSH *)va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Data Segment Header :\n\t- ID Mem = %d\n\t- Start = %p\n\t- Size = %d bytes", + DSH->MemID, DSH->Start, DSH->Size); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, SM_Root_Description_Get ("Data Segment Root", Root)); + + return NDS_OK; + + } + + if (Command == NDD_CMD_COMP_VALUE) + { + int comp; + + SMT_DSH * DSH1 = (SMT_DSH *)va_arg (Args, void *); + SMT_DSH * DSH2 = (SMT_DSH *)va_arg (Args, void *); + + va_end (Args); + + comp = (unsigned int)DSH1 - (unsigned int)DSH2; + + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + return NDS_EQUAL; + + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + SMT_DSH * DSH = (SMT_DSH *)va_arg (Args, void *); + + return SM_DataSegment_End (Root, DSH); + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Création d'un nouveau segment de données */ +/*------------------------------------------------------------------------------*/ +SMT_DSH * SM_DataSegment_Init ( SMT_MHH * MHH, size_t Segment_Size) +{ + SMT_DSH * New_DSH; + NDT_Node * Chunk_Node; + SMT_Chunk * Chunk; + + /* On vérifie que le heap n'atteint pas sa limite */ + + if (MHH->Limit_Size != SMD_UNLIMITED) + { + size_t Current_Size; + + ND_DataStruct_Traverse (MHH->DSR, NDD_CMD_SUM_VALUES, (void *)&Current_Size); + + if (Current_Size + Segment_Size > MHH->Limit_Size) + { + sprintf (SM_Error_Msg, "SM_DataSegment_Init : the heap limit size would be exceeded"); + SM_Error_Print (); + + return NULL; + } + } + + /* Création de l'entête */ + + if (ND_Allocator_Exec (MHH->DSR->Allocator, (void **)(&New_DSH), sizeof (SMT_DSH), NULL) != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_DataSegment_Init : unable to allocate memory for the new data segment header"); + SM_Error_Print (); + + return NULL; + } + + /* Création d'un segment de mémoire partagée */ + + if ((New_DSH->MemID = shmget (IPC_PRIVATE, Segment_Size, 0777|IPC_CREAT|IPC_EXCL)) == -1) + { + switch (errno) + { + case EINVAL: + sprintf (SM_Error_Msg, "SM_DataSegment_Init : the size of the shared memory segment (%d) is out of the system-imposed bounds", Segment_Size); + break; + + case ENOMEM: + sprintf (SM_Error_Msg, "SM_DataSegment_Init : the amount of memory is not sufficient to create the shared memory segment"); + break; + + case ENOSPC: + sprintf (SM_Error_Msg, "SM_DataSegment_Init : the number of shared memory segments exceeds the system-imposed limit"); + break; + + default : + sprintf (SM_Error_Msg, "SM_DataSegment_Init : unknown error (%d) while creating a shared memory segment", errno); + break; + } + + SM_Error_Print (); + + ND_Desallocator_Exec (MHH->DSR->Desallocator, New_DSH, NULL); + + return NULL; + } + + /* On attache le segment de mémoire partagée au processus courant */ + + errno = 0; + New_DSH->Start = shmat (New_DSH->MemID, (void *)((size_t)(SM_Base->Attach) - Segment_Size), SHM_RND); + if (errno) + { + sprintf (SM_Error_Msg, "SM_DataSegment_Init : unable to attach the shared memory segment to the current process (error %d)", errno); + SM_Error_Print (); + + shmctl (New_DSH->MemID, IPC_RMID, 0); + + ND_Desallocator_Exec (MHH->DSR->Desallocator, New_DSH, NULL); + + return NULL; + } + + SM_Base->Attach = New_DSH->Start; + + /* Initialisation des informations de l'entête */ + + New_DSH->Size = Segment_Size; + + /* Création d'un chunk libre au début du segment de données */ + + Chunk_Node = (NDT_Node *)New_DSH->Start; + + Chunk = (SMT_Chunk *)((size_t)Chunk_Node + sizeof (NDT_Node) ); + + Chunk_Node->Value = Chunk; + + Chunk->Data = (void *)((size_t)Chunk + sizeof (SMT_Chunk) ); + + Chunk->Size = New_DSH->Size - sizeof (NDT_Node) - sizeof (SMT_Chunk); + + /* Ajout du chunk libre à la liste des chunks libres du heap */ + + if (ND_Node_Add (MHH->FCR, Chunk_Node) != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_DataSegment_Init : unable to add a first chunk to the FCR structure of heap \"%s\"", MHH->Name); + SM_Error_Print (); + + shmctl (New_DSH->MemID, IPC_RMID, 0); + + ND_Desallocator_Exec (MHH->DSR->Desallocator, New_DSH, NULL); + + return NULL; + } + + return New_DSH; +} + +/*------------------------------------------------------------------------------*/ +/* Terminaison d'un segment de données */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_DataSegment_End (NDT_Root * Root, SMT_DSH *DSH) +{ + SMT_Status rc; + + /* Destruction du segment de mémoire partagée du segment de données */ + + if (shmctl (DSH->MemID, IPC_RMID, 0) == -1) + { + switch (errno) + { + case EPERM: + sprintf (SM_Error_Msg, "SM_DataSegment_End : current process (%d) is not allowed to destroy the shared memory segment %d", (int)getpid (), DSH->MemID); + break; + + case EINVAL: + sprintf (SM_Error_Msg, "SM_DataSegment_End : no shared memory segment exists for identifier %d", DSH->MemID); + break; + + default : + sprintf (SM_Error_Msg, "SM_DataSegment_End : unknown error %d while destroying the shared memory segment %d", errno, DSH->MemID); + break; + } + + SM_Error_Print (); + + return SMS_ERRSHM; + } + + /* Désallocation de l'entête */ + + rc = ND_Desallocator_Exec (Root->Desallocator, DSH, NULL); + if (rc != NDS_OK) + { + sprintf (SM_Error_Msg, "SM_DataSegment_End : the data segment header is nul"); + SM_Error_Print (); + + return rc; + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ouverture d'un segment de données */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_DataSegment_Open ( SMT_DSH *DSH) +{ + void *Ptr; + + /* + On attache le segment de mémoire partagée au processus courant. + + Attention : il faut que ce segment soit attaché à la même adresse + que lorsqu'il a été créé afin que les pointeurs qui pointent dans + ce segment soient valides. + */ + + shmdt ((void *)DSH->Start); + + errno = 0; + Ptr = shmat (DSH->MemID, DSH->Start, 0); + if (errno) + { + sprintf (SM_Error_Msg, "SM_DataSegment_Open : unable to attach the shared memory segment at the specified address %p (error %d)", DSH->Start, errno); + SM_Error_Print (); + + return SMS_ERRSHM; + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un segment de données */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_DataSegment_Close ( SMT_DSH *DSH) +{ + /* On détache le segment de mémoire partagée du processus courant */ + + shmdt ((void *)DSH->Start); + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Compression d'un segment de données */ +/*------------------------------------------------------------------------------*/ +size_t SM_DataSegment_Compress ( SMT_DSH *DSH, NDT_Root *FCR) +{ + size_t Total_Compress = 0; + size_t Compress; + SMT_Chunk *Chunk, *Next_Chunk; + NDT_Node * Node, *Next_Node; + void *DSH_End; + int Found = FALSE; + + DSH_End = (void *)((size_t)(DSH->Start) + DSH->Size); + + /* Recherche du premier chunk libre contenu dans le segment courant */ + + ND_Node_First_Get (FCR, &Node); + + while (Found == FALSE && Node) + { + if (Node > (NDT_Node *)DSH_End) Node = NULL; + else + { + if (Node >= (NDT_Node *)(DSH->Start)) Found = TRUE; + else ND_Node_Next_Get (Node, &Node); + } + } + + if (!Node) return 0; + + /* Parcours de tous les chunks libres du segment courant */ + + ND_Node_Next_Get (Node, &Next_Node); + + while (Next_Node && (void *)Next_Node < DSH_End) + { + Chunk = (SMT_Chunk *)(Node->Value); + + Next_Chunk = (SMT_Chunk *)(Next_Node->Value); + + /* Si le chunk suivant est "collé" au chunk courant, alors on les fusionne */ + + if (Next_Node == (NDT_Node *)((size_t)(Chunk->Data) + Chunk->Size)) + { + ND_Node_Remove (Next_Node); + + Compress = sizeof (SMT_Chunk) + sizeof (NDT_Node); + + Chunk->Size += Next_Chunk->Size + Compress; + + Total_Compress += Compress; + + ND_Node_Next_Get (Node, &Next_Node); + } + else + { + Node = Next_Node; + ND_Node_Next_Get (Next_Node, &Next_Node); + } + } + + return Total_Compress; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* Fonction de gestion de chunks */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Fonction manager pour un ACR (Allocated Chunk Root) */ +/*------------------------------------------------------------------------------*/ +NDT_Status SM_ACR_Manager (va_list Args) +{ + NDT_Command Command = (NDT_Command)va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_SUM_VALUES) + { + SMT_Chunk * Chunk = (SMT_Chunk *)va_arg (Args, void *); + int * Total_Size = (int *)va_arg (Args, int *); + + (*Total_Size) += Chunk->Size; + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + SMT_Chunk *Chunk = (SMT_Chunk *)va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Allocated chunk :\n\t- Size = %d\n\t- Data = %p", Chunk->Size, Chunk->Data); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, SM_Root_Description_Get ("Allocated Chunk Root", Root)); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + int comp; + SMT_Chunk *Chunk1 = (SMT_Chunk *)va_arg (Args, void *); + SMT_Chunk *Chunk2 = (SMT_Chunk *)va_arg (Args, void *); + + va_end (Args); + + /* Les chunks alloués sont triés sur le champ (adresse d'allocation) */ + + comp = (unsigned int)Chunk1->Data - (unsigned int)Chunk2->Data; + + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fonction manager pour un FCR (Free Chunk Root) */ +/*------------------------------------------------------------------------------*/ +NDT_Status SM_FCR_Manager (va_list Args) +{ + NDT_Command Command = (NDT_Command)va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_SUM_VALUES) + { + SMT_Chunk * Chunk = (SMT_Chunk *)va_arg (Args, void *); + int * Total_Size = (int *)va_arg (Args, int *); + + (*Total_Size) += Chunk->Size; + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + SMT_Chunk * Chunk = (SMT_Chunk *)va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Free Chunk :\n\t- Size = %d\n\t- Data = %p", Chunk->Size, Chunk->Data); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, SM_Root_Description_Get ("Free Chunk Root", Root)); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + int comp; + SMT_Chunk *Chunk1 = (SMT_Chunk *)va_arg (Args, void *); + SMT_Chunk *Chunk2 = (SMT_Chunk *)va_arg (Args, void *); + + va_end (Args); + + /* + La comparaison des chunks libres porte sur le champ + pour faciliter la compression des heaps. + */ + + comp = (unsigned int)(Chunk1->Data) - (unsigned int)(Chunk2->Data); + + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + return NDS_EQUAL; + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Pose d'un verrou sur un heap */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Lock_Set ( SMT_MHH * MHH, SMT_Flags Lock_Mode ) +{ + SMT_Status rc; + + if (Lock_Mode & SMD_READ) + { + rc = SM_Semaphore_Operate (MHH->SemID, SM_SemOp_SSL, 2); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock_Set : unable to lock the heap for reading"); + SM_Error_Print (); + + return rc; + } + } + + if (Lock_Mode & SMD_WRITE) + { + rc = SM_Semaphore_Operate (MHH->SemID, SM_SemOp_SEL, 2); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock_Set : unable to lock the heap for writing"); + SM_Error_Print (); + + return rc; + } + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Changement d'un verrou sur un heap */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Lock_Change ( SMT_MHH * MHH, SMT_Flags Lock_Mode ) +{ + SMT_Status rc; + + if (Lock_Mode & SMD_WRITE) + { + /* + Attention : il ne faut pas tenter de transformer directement un verrou en lecture en + un verrou en écriture car cela pourrait aboutir à un deadlock entre deux processus + qui voudraient réaliser cette opération en même temps. + + => On passe donc par un déverrouillage intermédiaire. + */ + + if ((rc = SM_Semaphore_Operate (MHH->SemID, SM_SemOp_RSL, 2)) != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock_Change : unable to transform the heap lock for writing"); + SM_Error_Print (); + + return rc; + } + + if ((rc = SM_Semaphore_Operate (MHH->SemID, SM_SemOp_SEL, 2)) != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock_Change : unable to transform the heap lock for writing"); + SM_Error_Print (); + + /* On tente de revenir à l'état de verrouillage précédent */ + + SM_Semaphore_Operate (MHH->SemID, SM_SemOp_SSL, 2); + + return rc; + } + } + else if (Lock_Mode & SMD_READ) + { + rc = SM_Semaphore_Operate (MHH->SemID, SM_SemOp_TSL, 2); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock_Change : unable to transform the heap lock for reading"); + SM_Error_Print (); + + return rc; + } + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Libération d'un verrou sur un heap */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Lock_Release ( SMT_MHH * MHH, SMT_Flags Lock_Mode ) +{ + SMT_Status rc; + + if (Lock_Mode & SMD_READ) + { + rc = SM_Semaphore_Operate (MHH->SemID, SM_SemOp_RSL, 2); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock_Release : unable to unlock the heap which had been locked for reading"); + SM_Error_Print (); + + return rc; + } + } + + if (Lock_Mode & SMD_WRITE) + { + rc = SM_Semaphore_Operate (MHH->SemID, SM_SemOp_REL, 2); + if (rc != SMS_OK) + { + sprintf (SM_Error_Msg, "SM_Heap_Lock_Release : unable to unlock the heap which had been locked for writing"); + SM_Error_Print (); + + return rc; + } + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Opération sur un sémaphore */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Semaphore_Operate (int SemID, struct sembuf * Operations, unsigned int Nb_Oper) +{ + if (semop (SemID, Operations, Nb_Oper) == -1) + { + switch (errno) + { + case EAGAIN: + sprintf (SM_Error_Msg, "SM_Semaphore_Operate : the operation would result in suspension of the calling process but the operations have been defined in no wait mode"); + return SMS_NO_WAIT; + break; + + case EACCES: + sprintf (SM_Error_Msg, "SM_Semaphore_Operate : current process is not allowed to operate on semaphore %d", SemID); + break; + + case EIDRM: + sprintf (SM_Error_Msg, "SM_Semaphore_Operate : semaphore %d does not exist", SemID); + break; + + case EINTR: + sprintf (SM_Error_Msg, "SM_Semaphore_Operate : a signal was received while operating on semaphore %d", SemID); + return SMS_ERRSIG; + break; + + case EINVAL: + sprintf (SM_Error_Msg, "SM_Semaphore_Operate : the semaphore identifier %d is incorrect or the number of operations which can be done in UNDO mode exceeds the system-imposed limit", SemID); + break; + + case ENOSPC: + sprintf (SM_Error_Msg, "SM_Semaphore_Operate : the maximum number of process which can operate on semaphore in UNDO mode has been reached"); + break; + + case ERANGE: + sprintf (SM_Error_Msg, "SM_Semaphore_Operate: the value of semaphore %d has reached the system-imposed limit", SemID); + break; + + default : + sprintf (SM_Error_Msg, "SM_Semaphore_Operate : unknown error %d while operating on semaphore %d", errno, SemID); + break; + } + + SM_Error_Print (); + + return SMS_ERRSEM; + } + + return SMS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupère sous forme explicite l'état d'un verrou */ +/*------------------------------------------------------------------------------*/ +char * SM_Lock_Status_Get ( const char * Type, void * Struct) +{ + static char Status [50]; + int i, SemID; + pid_t Writer; + union semun Sem_Ctl; + + if (!strcmp (Type, "base")) + { + SemID = SM_Base->SemID; + Writer = SM_Base->Writer; + } + else if (!strcmp (Type, "heap")) + { + SMT_MHH * MHH = (SMT_MHH *)Struct; + + SemID = MHH->SemID; + Writer = MHH->Writer; + } + else + { + strcpy (Status, "unknown"); + return Status; + } + + i = semctl (SemID, 0, GETVAL, Sem_Ctl); + + switch (i) + { + case 0: + sprintf (Status, "exclusive lock (process id = %ld)", Writer); + break; + + case 1: + sprintf (Status, "unlocked"); + break; + + default : + if (i < 0) + sprintf (Status, "anormal status (%d)", i); + else + sprintf (Status, "share lock (%d process)", i - 1); + break; + } + + return Status; +} + +/*------------------------------------------------------------------------------*/ +/* Récupère sous forme explicite la description d'une racine de structure */ +/*------------------------------------------------------------------------------*/ +char * SM_Root_Description_Get ( const char * Root_Label, NDT_Root * Root ) +{ + char * Root_Type; + static char Root_Info [256]; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "ordered list"; break; + case NDD_MN_FILO : Root_Type = "FILO list"; break; + case NDD_MN_FIFO : Root_Type = "FIFO list"; break; + default : Root_Type = "unknown"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "auto-equalized tree"; break; + default : Root_Type = "non-auto-equalized tree"; break; + } + break; + + default : Root_Type = "unknown"; break; + } + + sprintf (Root_Info, "%s :\n\t- Structure type = %s\n\t- Node number = %ld\n", Root_Label, Root_Type, Root->Node_Number); + + return Root_Info; +} + +/*------------------------------------------------------------------------------*/ +/* Routine d'affichage d'un message d'erreur */ +/*------------------------------------------------------------------------------*/ +void SM_Error_Print ( void ) +{ + if (SM_stderr) fprintf (SM_stderr, "Error %s\n", SM_Error_Msg); +} + +/*------------------------------------------------------------------------------*/ +/* Pour préfixer un nom de heap avec le nom du contexte d'utilisation */ +/*------------------------------------------------------------------------------*/ +static char * SM_Name_Prefix ( const char * Name) +{ + static char Prefixed [256]; + + if (!SM_Context || !strlen (SM_Context) || !strcmp (Name, HEAP_SYSTEM)) + strcpy (Prefixed, Name); + else + sprintf (Prefixed, "%s/%s", SM_Context, Name); + + return Prefixed; +} diff --git a/lib/libshmem.h b/lib/libshmem.h new file mode 100644 index 0000000..8f55482 --- /dev/null +++ b/lib/libshmem.h @@ -0,0 +1,263 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Compteur d'ouverture de la librairie */ + +unsigned int SM_Open_Counter = 0; + +/* Flux de sortie des messages d'erreur générés par la librairie */ + +FILE * SM_stderr; + +extern char * strdup (const char *); + +#define max(A,B) ((A < B) ? B : A) + +/* Limite supérieure d'adressage */ + +#define MEM_LIMIT 1000000000 + +/* Taille d'un segment = 100 Ko par défaut */ + +#define K 1024 +#define NB_BLOCS 100 +#define SEGMENT_DEFAULT_SIZE NB_BLOCS * K + +char Info_Msg [256]; + +/* Etats possibles pour un heap */ + +#define SMD_STATE_VALID 0 +#define SMD_STATE_UNVALIDATED 1 +#define SMD_STATE_CORRUPTED 2 + +/* Référence sur le heap système */ + +SMT_Heap * System_Heap; + +/* Liste des heaps ouverts par le processus courant */ + +NDT_Root * Opened_Heap_List; + +/* + Taille par défaut des chunks alloués dans le heap système : + Cette taille est fixée à la taille maximale des chunks pouvant + y être alloué (de type NDT_Node, NDT_Root, SMT_MHH ou SMT_DSH) +*/ + +#define DEFAULT_CHUNK_SIZE max(max(sizeof(NDT_Root), sizeof(NDT_Node)), max(sizeof(SMT_MHH), sizeof(SMT_DSH))) + +/* + Nombre de chunk libre minimum avant extension du heap système par un + nouveau segment de données (fixé à 3 car l'ajout d'un nouveau segment + nécessite l'allocation de 2 chunks (un noeud et une entête de segment). +*/ + +#define FREE_CHUNK_LIMIT 3 + +int SM_Instance; +char * SM_Context; + +/* Contexte et instance d'utilisation de la librairie */ + +#define DEFAULT_INSTANCE 1000 +#define INSTANCE_ENV_VAR "INSTANCE" + +#define DEFAULT_CONTEXT "CTX" +#define CONTEXT_ENV_VAR "CONTEXT" + +/* + Variable globale permettant d'indiquer que l'on est en train + d'étendre le heap système par ajout d'un nouveau segment. +*/ + +unsigned int Adding_Segment = FALSE; + +SMT_Chunk * Tmp_Chunk; +SMT_MHH * Tmp_MHH; + +/* + Définition des opérations de verouillage et de déverrouillage + NB : la valeur 1 d'un sémaphore correspond à l'état non verrouillé +*/ + +/* Pose d'un verrou en lecture : 2 opérations : ( -1 puis +2 ) */ + +struct sembuf SM_SemOp_SSL [2] = { {0, -1, SEM_UNDO}, {0, 2, SEM_UNDO} }; + +/* Libération d'un verrou en lecture : 2 opérations ( -2 puis +1 ) */ + +struct sembuf SM_SemOp_RSL [2] = { {0, -2, SEM_UNDO|IPC_NOWAIT}, {0, 1, SEM_UNDO|IPC_NOWAIT} }; + +/* Pose d'un verrou en écriture : 2 opérations ( -1 puis 0 ) */ + +struct sembuf SM_SemOp_SEL [2] = { {0, -1, SEM_UNDO}, {0, 0, SEM_UNDO} }; + +/* Libération d'un verrou en écriture : 2 opérations ( 0 puis +1 ) */ + +struct sembuf SM_SemOp_REL [2] = { {0, 0, SEM_UNDO|IPC_NOWAIT}, {0, 1, SEM_UNDO|IPC_NOWAIT} }; + +/* Transformation d'un verrou en écriture en un verrou en lecture : 2 opérations ( 0 puis +2 ) */ + +struct sembuf SM_SemOp_TSL [2] = { {0, 0, SEM_UNDO|IPC_NOWAIT}, {0, 2, SEM_UNDO|IPC_NOWAIT} }; + +typedef union semun +{ + int val; + struct semid_ds * buf; + unsigned short int * array; +} semun; + +/*------------------------------------------------------------------------------*/ +/* Allocation de mémoire dans la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Alloc (size_t, void **, void *); + +/*------------------------------------------------------------------------------*/ +/* Désallocation de mémoire dans la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Free (void *, void *); + +/*------------------------------------------------------------------------------*/ +/* Allocation de mémoire dans le heap système */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_System_Alloc (size_t, void **, void *); + +/*------------------------------------------------------------------------------*/ +/* Désallocation de mémoire dans le heap système */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_System_Free (void *, void *); + +/*------------------------------------------------------------------------------*/ +/* Initialisation de la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Init (void); + +/*------------------------------------------------------------------------------*/ +/* Terminaison de la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_End (void); + +/*------------------------------------------------------------------------------*/ +/* Ouverture de la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Open (void); + +/*------------------------------------------------------------------------------*/ +/* Fermeture de la base */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Close (void); + +/*------------------------------------------------------------------------------*/ +/* Pose d'un verrou sur la base : */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Lock (SMT_Flags); + +/*------------------------------------------------------------------------------*/ +/* Libération d'un verrou sur la base : */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Base_Unlock (SMT_Flags); + +/*------------------------------------------------------------------------------*/ +/* Fonction manager de la liste des heaps ouverts */ +/*------------------------------------------------------------------------------*/ +NDT_Status SM_Opened_Heap_List_Manager (va_list); + +/*------------------------------------------------------------------------------*/ +/* Fonction manager du MHR (Memory Heap Root) */ +/*------------------------------------------------------------------------------*/ +NDT_Status MHR_Manager (va_list); + +/*------------------------------------------------------------------------------*/ +/* Destruction d'un MHH (Memory Heap Header) */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_MHH_End (SMT_MHH *); + +/*------------------------------------------------------------------------------*/ +/* Fonction manager pour un DSR (Data Segment Root) */ +/*------------------------------------------------------------------------------*/ +NDT_Status SM_DSR_Manager (va_list); + +/*------------------------------------------------------------------------------*/ +/* Initialisation d'un nouveau segment de données (noeud du DSR) */ +/*------------------------------------------------------------------------------*/ +SMT_DSH *SM_DataSegment_Init (SMT_MHH *, size_t); + +/*------------------------------------------------------------------------------*/ +/* Terminaison d'un segment de données */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_DataSegment_End (NDT_Root *, SMT_DSH *); + +/*------------------------------------------------------------------------------*/ +/* Ouverture d'un segment de données */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_DataSegment_Open (SMT_DSH *); + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un segment de données */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_DataSegment_Close (SMT_DSH *); + +/*------------------------------------------------------------------------------*/ +/* Compression d'un segment de données */ +/*------------------------------------------------------------------------------*/ +size_t SM_DataSegment_Compress (SMT_DSH *, NDT_Root *); + +/*------------------------------------------------------------------------------*/ +/* Fonction manager pour un ACR (Allocated Chunk Root) */ +/*------------------------------------------------------------------------------*/ +NDT_Status SM_ACR_Manager (va_list); + +/*------------------------------------------------------------------------------*/ +/* Fonction manager pour un FCR (Free Chunk Root) */ +/*------------------------------------------------------------------------------*/ +NDT_Status SM_FCR_Manager(va_list); + +/*------------------------------------------------------------------------------*/ +/* Pose d'un verrou sur un heap : */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Lock_Set (SMT_MHH *, SMT_Flags); + +/*------------------------------------------------------------------------------*/ +/* Changement d'un verrou sur un heap : */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Lock_Change (SMT_MHH *, SMT_Flags); + +/*------------------------------------------------------------------------------*/ +/* Libération d'un verrou sur un heap : */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Heap_Lock_Release (SMT_MHH *, SMT_Flags); + +/*------------------------------------------------------------------------------*/ +/* Opération sur un sémaphore */ +/*------------------------------------------------------------------------------*/ +SMT_Status SM_Semaphore_Operate (int, struct sembuf *, unsigned int); + +/*------------------------------------------------------------------------------*/ +/* Récupère sous forme explicite l'état d'un verrou */ +/*------------------------------------------------------------------------------*/ +char * SM_Lock_Status_Get (const char *, void *); + +/*------------------------------------------------------------------------------*/ +/* Récupère sous forme explicite la description d'une racine de structure */ +/*------------------------------------------------------------------------------*/ +char * SM_Root_Description_Get (const char *, NDT_Root *); + +/*------------------------------------------------------------------------------*/ +/* Routine d'affichage d'un message d'erreur */ +/*------------------------------------------------------------------------------*/ +void SM_Error_Print (void); + +/*------------------------------------------------------------------------------*/ +/* Pour préfixer un nom de heap avec le nom de l'instance utilisée */ +/*------------------------------------------------------------------------------*/ +static char * SM_Name_Prefix (const char *); diff --git a/util/smadmin.c b/util/smadmin.c new file mode 100644 index 0000000..9438f5f --- /dev/null +++ b/util/smadmin.c @@ -0,0 +1,341 @@ +#include +#include +#include +#include +#include +#define SM_MODE 0 /* Utilisation des API sécurisés */ +#include + +VER_INFO_EXPORT (smadmin, "$Revision: 1.1 $", "$Name: $", __FILE__, "$Author: smas $") + +#define USAGE "Usage : %s [ --help | --version [-v] | --create | --destroy ]\n" + +#define QUIT 0 +#define BASE_INIT 1 +#define BASE_OPEN 2 +#define BASE_INFO 3 +#define BASE_CLOSE 4 +#define BASE_END 5 +#define MHH_INIT 6 +#define MHH_OPEN 7 +#define MHH_CHECK 8 +#define MHH_COMPRESS 9 +#define MHH_CLOSE 10 +#define MHH_END 11 +#define ALLOC_CHUNK 12 +#define WRITE_CHUNK 13 +#define READ_CHUNK 14 +#define FREE_CHUNK 15 +#define DSR_DUMP 16 +#define ACR_DUMP 17 +#define FCR_DUMP 18 + +char menu [1000]; +char tmp [100]; + +void init_menu (void); +int print_menu (void); + +int main (int argc, char ** argv) +{ + int choice; + char name [100]; + int Mode, Locked; + void * ptr; + char answer [10]; + SMT_Heap * Heap; + int Nb_Detected, Nb_Corrected; + size_t size; + + /* Lancement de commande d'administration */ + + if (argc >= 2) + { + if (!strcmp (argv[1], "--help")) + { + fprintf (stderr, USAGE, argv[0]); + return -1; + } + else if (!strcmp (argv[1], "--version")) + { + if (argc >= 3 && !strcmp (argv[2], "-v")) + return VER_Object_Print (stdout, VERD_VERBOSE); + else + return VER_Object_Print (stdout, VERD_MINIMAL); + } + else if (!strcmp (argv[1], "--create")) + { + if (SM_Library_Open (0, NULL, SMD_CREATE | SMD_DEBUG_ALL) != SMS_OK) + { + fprintf (stderr, "=> Impossible de créer l'instance de la librairie LIBSHMEM\n"); + return -1; + } + + return 0; + } + else if (!strcmp (argv[1], "--destroy")) + { + if (SM_Library_Open (0, NULL, SMD_OPEN | SMD_DEBUG_ALL) != SMS_OK || SM_Library_Close (SMD_DESTROY) != SMS_OK) + { + fprintf (stderr, "=> Impossible de détruire l'instance de la librairie LIBSHMEM\n"); + return -1; + } + return 0; + } + else + { + fprintf (stderr, USAGE, argv[0]); + return -1; + } + } + + /* Lancement du menu intercatif */ + + init_menu (); + + choice = print_menu (); + + while (choice != QUIT) + { + strcpy (answer, "yes"); + + switch (choice) + { + case BASE_INIT: + fprintf (stdout, "\nReturn code = %s\n", \ + SM_Library_Open (0, NULL, SMD_CREATE | SMD_DEBUG_ALL) == SMS_OK ? "OK" : "NOK" ); + break; + + case BASE_OPEN: + fprintf (stdout, "\nReturn code = %s\n", \ + SM_Library_Open (0, NULL, SMD_OPEN | SMD_DEBUG_ALL) == SMS_OK ? "OK" : "NOK" ); + break; + + case BASE_END: + fprintf (stdout, "\nReturn code = %s\n", \ + SM_Library_Close (SMD_DESTROY) == SMS_OK ? "OK" : "NOK" ); + break; + + case BASE_CLOSE: + fprintf (stdout, "\nReturn code = %s\n", \ + SM_Library_Close (SMD_CLOSE) == SMS_OK ? "OK" : "NOK" ); + break; + + case BASE_INFO: + SM_Library_Dump (stderr); + break; + + case MHH_INIT: + fprintf (stdout, "\nNew heap name ? "); + gets (name); + fprintf (stdout, "\nHeap segment size ? "); + gets (tmp); + size = atoi (tmp); + fprintf (stdout, "\nReturn code = %s\n", \ + SM_Heap_Open (name, &Heap, size, \ + SMD_CREATE, &Locked) == SMS_OK ? "OK" : "NOK" ); + break; + + case MHH_OPEN: + fprintf (stdout, "\nHeap name to open ? "); + gets (name); + fprintf (stdout, "\nOpening mode (read=1 write=2) ? "); + gets (tmp); + if (tmp[0] == '1') Mode = SMD_READ; + else Mode = SMD_WRITE; + if (!strcmp (name, HEAP_SYSTEM)) + { + fprintf (stdout, \ + "\n*** Warning : you can not make this operation on the system heap ***\n"); + break; + } + + fprintf (stdout, "\nReturn code = %s\n", SM_Heap_Open (name, \ + &Heap, 0, SMD_OPEN | Mode, &Locked) == SMS_OK ? "OK" : "NOK" ); + + break; + + case MHH_COMPRESS: + fprintf (stdout, "\nHeap name à compresser ? "); + gets (name); + if (SM_Heap_Open (name, &Heap, 0, SMD_OPEN | SMD_WRITE, &Locked) == SMS_OK) + { + size_t Compress; + SM_Heap_Compress (Heap, &Compress); + fprintf (stdout, "\nCompression size = %d byte(s)\n", (int)Compress); + if (Locked == TRUE) SM_Heap_Unlock (Heap); + } + break; + + case MHH_END: + fprintf (stdout, "\nHeap name to remove ? "); + gets (name); + if (!strcmp (name, HEAP_SYSTEM)) + { + fprintf (stdout, \ + "\n*** Warning : you can not make this operation on the system heap ***\n"); + break; + } + + fprintf (stdout, "\nReturn code = %s\n", \ + SM_Heap_End (name) == SMS_OK ? "OK" : "NOK" ); + + break; + + case MHH_CLOSE: + fprintf (stdout, "\nHeap name to close ? "); + gets (name); + if (!strcmp (name, HEAP_SYSTEM)) + { + fprintf (stdout, \ + "\n*** Warning : you can not make this operation on the system heap ***\n"); + break; + } + if (SM_Heap_IsOpen (name, &Heap) == SMS_OK) + fprintf (stdout, "\nReturn code = %s\n", \ + SM_Heap_Close (Heap) == SMS_OK ? "OK" : "NOK" ); + else + fprintf (stdout, "\nHeap %s is not opened\n", name); + + break; + + case MHH_CHECK: + fprintf (stdout, "\nHeap name to check/recover ? "); + gets (name); + if (SM_Heap_Open (name, &Heap, 0, SMD_OPEN | SMD_WRITE, &Locked) == SMS_OK) + { + Nb_Detected = Nb_Corrected = 0; + SM_Heap_Check (Heap, &Nb_Detected, &Nb_Corrected, stderr); + if (Locked == TRUE) SM_Heap_Unlock (Heap); + } + break; + + case ALLOC_CHUNK: + fprintf (stdout, "\nHeap name ? "); + gets (name); + fprintf (stdout, "\nAllocation size ? "); + gets (tmp); + size = atoi (tmp); + if (SM_Heap_Open (name, &Heap, 0, SMD_OPEN | SMD_WRITE, &Locked) == SMS_OK) + { + SM_Chunk_Alloc (Heap, size, &ptr); + if (Locked == TRUE) SM_Heap_Unlock (Heap); + } + fprintf (stdout, "\nAddress = 0x%p (%d)\n", ptr, (unsigned int)ptr); + break; + + case WRITE_CHUNK: + fprintf (stdout, "\nAddress ? "); + gets (tmp); + ptr = (void *)atoi (tmp); + fprintf (stdout, "\nString to put in ? "); + gets (tmp); + strcpy ( (char *)ptr, tmp); + fprintf (stdout, "\nOK\n"); + break; + + case READ_CHUNK: + fprintf (stdout, "\nAddress ? "); + gets (tmp); + ptr = (void *)atoi (tmp); + fprintf (stdout, "\nValeur du pointeur = %s\n", (char *)ptr); + break; + + case FREE_CHUNK: + fprintf (stdout, "\nHeap name ? "); + gets (name); + fprintf (stdout, "\nAddress ? "); + gets (tmp); + ptr = (void *)atoi (tmp); + if (SM_Heap_Open (name, &Heap, 0, SMD_OPEN | SMD_WRITE, &Locked) == SMS_OK) + { + fprintf (stdout, "\nReturn code = %s\n", \ + SM_Chunk_Free (Heap, ptr) == SMS_OK ? "OK" : "NOK" ); + if (Locked == TRUE) SM_Heap_Unlock (Heap); + } + + break; + + case DSR_DUMP: + fprintf (stdout, "\nHeap name ? "); + gets (name); + if (SM_Heap_Open (name, &Heap, 0, SMD_OPEN | SMD_READ, &Locked) == SMS_OK) + { + ND_DataStruct_Info_Print (Heap->MHH->DSR, stdout); + ND_DataStruct_Print (Heap->MHH->DSR, stdout); + if (Locked == TRUE) SM_Heap_Unlock (Heap); + } + break; + + case ACR_DUMP: + fprintf (stdout, "\nHeap name ? "); + gets (name); + if (SM_Heap_Open (name, &Heap, 0, SMD_OPEN | SMD_READ, &Locked) == SMS_OK) + { + ND_DataStruct_Info_Print (Heap->MHH->ACR, stdout); + ND_DataStruct_Print (Heap->MHH->ACR, stdout); + if (Locked == TRUE) SM_Heap_Unlock (Heap); + } + break; + + case FCR_DUMP: + fprintf (stdout, "\nHeap name ? "); + gets (name); + if (SM_Heap_Open (name, &Heap, 0, SMD_OPEN | SMD_READ, &Locked) == SMS_OK) + { + ND_DataStruct_Info_Print (Heap->MHH->FCR, stdout); + ND_DataStruct_Print (Heap->MHH->FCR, stdout); + if (Locked == TRUE) SM_Heap_Unlock (Heap); + } + break; + + case QUIT: + fprintf (stdout, "\nExiting program ...\n"); + break; + + default: + fprintf (stdout, "\nUndefined choice %d\n", choice); + } + choice = print_menu (); + } + return 0; +} + +void init_menu (void) +{ + sprintf (menu, "Menu :\n"); + sprintf (tmp, " - %2d) %-18s\n", QUIT, "Quit"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", BASE_INIT, "Init library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", BASE_OPEN, "Open library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s\n", BASE_INFO, "Info library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", BASE_CLOSE, "Close library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", BASE_END, "End library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s\n", MHH_INIT, "Init heap"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", MHH_OPEN, "Open heap"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", MHH_CHECK, "Check/recover heap"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s\n", MHH_COMPRESS, "Compress heap"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", MHH_CLOSE, "Close heap"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", MHH_END, "End heap"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s\n", ALLOC_CHUNK, "Allocate chunk"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", WRITE_CHUNK, "Write chunk"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", READ_CHUNK, "Read chunk"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s\n", FREE_CHUNK, "Free chunk"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", DSR_DUMP, "Dump DSR"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s", ACR_DUMP, "Dump ACR"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-18s\n", FCR_DUMP, "Dump FCR"); strcat (menu, tmp); +} + +int print_menu (void) +{ + fprintf (stdout, "------------------------------------------------------\n%s", menu); + + tmp[0] = '\0'; + while (tmp[0] == '\0') + { + printf ("\nChoice ? "); + gets (tmp); + } + + return atoi (tmp); +} +