commit 991dc2df52145828001259fd8064cff53d885b7a Author: smas Date: Fri Jul 28 14:13:54 2000 +0000 Première version diff --git a/doc/libshmem.doc b/doc/libshmem.doc new file mode 100644 index 0000000..485a7bf Binary files /dev/null and b/doc/libshmem.doc differ diff --git a/doc/man3/libshmem.3 b/doc/man3/libshmem.3 new file mode 100644 index 0000000..fc44dd3 --- /dev/null +++ b/doc/man3/libshmem.3 @@ -0,0 +1,588 @@ +'\" t +.\" @(#)LIBSM.3 99/10/27 SMA; +.TH LIBSM 3 "27 Oct 1999" +.SH NOM +LIBSM (librairie de memoires partagees) +.SH SYNOPSIS +.LP +.BI "cc [flag ...] file ... -lver -ldl -lnode -lshmem [library ...]" +.LP +.BI "#include " +.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); +} +