3848 lines
123 KiB
C
3848 lines
123 KiB
C
/* Utilisation des API de la LIBNODE sans vérification des arguments */
|
|
|
|
#define ND_MODE 1
|
|
|
|
#include <libshmem.h>
|
|
|
|
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 <Data> (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 <Data>
|
|
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;
|
|
}
|