/****************************************
* Sebastien Leriche, Antoine Jacquet *
* Module de gestion memoire *
* Niveau 4 *
****************************************/
#include <stdlib.h>
#include <string.h>
#include "memoire.h"
int cpt_malloc=0, cpt_free=0;
char politique='f';
FILE *fhistorique=NULL;
struct liste_tas *existe_tas(char ident[], struct liste_tas *bus)
/* Renvoie un pointeur sur le tas de nom ident dans la liste des tas pointee par bus ou NULL sinon */
{
while (bus!=NULL)
{
if (strcmp(bus->tas.ident,ident)==0) return(bus);
bus=bus->p_suivant;
}
return(NULL);
}
int initialiser(int t,struct memoire **pp_memoire)
/* Initialise la memoire
Retourne -1 en cas d'erreur, 0 sinon */
{
struct liste_libre *p_liste_libre;
fprintf(fhistorique," initialiser %d\n",t);
*pp_memoire=malloc(sizeof(struct memoire));
if (*pp_memoire==NULL)
{
fprintf(fhistorique," initialiser : erreur de malloc !\n");
return(-1);
}
cpt_malloc++;
(*pp_memoire)->mem=malloc(t);
if ((*pp_memoire)->mem==NULL)
{
fprintf(fhistorique," initialiser : erreur de malloc !\n");
return(-1);
}
cpt_malloc++;
p_liste_libre=malloc(sizeof(struct liste_libre));
if (p_liste_libre==NULL)
{
fprintf(fhistorique," initialiser : erreur de malloc !\n");
return(-1);
}
cpt_malloc++;
(*pp_memoire)->taille_memoire=t;
p_liste_libre->bloc.adresse=0;
p_liste_libre->bloc.taille=t;
p_liste_libre->p_suivant=NULL;
(*pp_memoire)->p_liste_libre=p_liste_libre;
(*pp_memoire)->p_liste_tas=NULL;
(*pp_memoire)->p_liste_programmes=NULL;
return(0);
}
int terminer(struct memoire **pp_memoire)
/* Libere correctement la memoire
Retourne -1 en cas de mauvaise gestion de la memoire, 0 sinon */
{
struct liste_libre *p_liste_libre=(*pp_memoire)->p_liste_libre;
struct liste_libre *bus_libre=p_liste_libre;
struct liste_tas *p_liste_tas=(*pp_memoire)->p_liste_tas;
struct liste_tas *bus_tas=p_liste_tas;
struct programme *p_liste_programmes=(*pp_memoire)->p_liste_programmes;
struct programme *bus_prog=p_liste_programmes;
fprintf(fhistorique," terminer\n");
while (bus_libre!=NULL)
{
p_liste_libre=(p_liste_libre)->p_suivant;
free(bus_libre);
cpt_free++;
bus_libre=p_liste_libre;
}
while (bus_tas!=NULL)
{
p_liste_tas=(p_liste_tas)->p_suivant;
free(bus_tas);
cpt_free++;
bus_tas=p_liste_tas;
}
while (bus_prog!=NULL)
{
p_liste_programmes=(p_liste_programmes)->p_suivant;
free(bus_prog);
cpt_free++;
bus_prog=p_liste_programmes;
}
free((*pp_memoire)->mem);
cpt_free++;
free(*pp_memoire);
cpt_free++;
*pp_memoire=NULL;
fprintf(fhistorique," terminer : cpt_malloc=%d, cpt_free=%d\n",cpt_malloc,cpt_free);
if (cpt_malloc==cpt_free)
{
fprintf(fhistorique," terminer : bonne gestion de la memoire\n");
return(0);
}
else
{
fprintf(fhistorique," terminer : mauvaise gestion de la memoire !\n");
return(-1);
}
}
/* Macro qui affecte a bus un pointeur qui contient la zone de memoire libre qui convient
en fonction de la politique, NULL sinon, ainsi que la cellule precedente dans cel_precedente */
#define ALLOUER_TROUVE_BLOC \
{ \
struct liste_libre *meilleur=NULL, *meilleur_cel_precedente=NULL; \
\
cel_precedente=NULL; \
bus=*pp_liste_libre; \
switch (politique) \
{ \
case 'f': \
while ((bus!=NULL) && (bus->bloc.taille<t)) \
{ \
cel_precedente=bus; \
bus=bus->p_suivant; \
} \
break; \
case 'b': \
while (bus!=NULL) \
{ \
if (bus->bloc.taille>=t) \
if ((meilleur==NULL) || (bus->bloc.taille<meilleur->bloc.taille)) \
{ \
meilleur_cel_precedente=cel_precedente; \
meilleur=bus; \
} \
cel_precedente=bus; \
bus=bus->p_suivant; \
} \
cel_precedente=meilleur_cel_precedente; \
bus=meilleur; \
break; \
case 'w': \
while (bus!=NULL) \
{ \
if (bus->bloc.taille>=t) \
if ((meilleur==NULL) || (bus->bloc.taille>meilleur->bloc.taille)) \
{ \
meilleur_cel_precedente=cel_precedente; \
meilleur=bus; \
} \
cel_precedente=bus; \
bus=bus->p_suivant; \
} \
cel_precedente=meilleur_cel_precedente; \
bus=meilleur; \
break; \
} \
}
/* Macro qui affiche le message d'erreur et quitte */
#define ALLOUER_ERREUR \
{ \
fprintf(fhistorique," allouer : pas de bloc assez grand !\n"); \
return(-1); \
}
int allouer(int t, struct memoire *p_memoire)
/* Alloue une zone memoire de taille t
Retourne son adresse, -1 sinon */
{
struct liste_libre **pp_liste_libre=&(p_memoire->p_liste_libre);
struct liste_libre *bus,*cel_precedente;
int adresse;
fprintf(fhistorique," allouer %d\n",t);
/* On essaie de trouver un bloc, en appelant les differents ramasse-miettes si necessaire */
ALLOUER_TROUVE_BLOC
if (bus==NULL)
{
if (ramasse_miettes_compteurs(p_memoire)==-1)
{
if (ramasse_miettes_marquage_balayage(p_memoire)==-1) ALLOUER_ERREUR
else
{
ALLOUER_TROUVE_BLOC
if (bus==NULL) ALLOUER_ERREUR
}
}
else
{
ALLOUER_TROUVE_BLOC
if (bus==NULL)
{
if (ramasse_miettes_marquage_balayage(p_memoire)==-1) ALLOUER_ERREUR
else
{
ALLOUER_TROUVE_BLOC
if (bus==NULL) ALLOUER_ERREUR
}
}
}
}
/* Allocation de la zone */
adresse=bus->bloc.adresse;
if (bus->bloc.taille==t)
{
if (cel_precedente==NULL) *pp_liste_libre=bus->p_suivant;
else cel_precedente->p_suivant=bus->p_suivant;
free(bus);
cpt_free++;
}
else
{
bus->bloc.taille-=t;
bus->bloc.adresse+=t;
}
fprintf(fhistorique," allouer : adresse=%d\n",adresse);
return(adresse);
}
int liberer(int adresse_libre, int taille_libre, struct memoire *p_memoire)
/* Libere la zone memoire de taille taille_libre a l'adresse adresse_libre
Retourne -1 en cas d'erreur, 0 sinon */
{
struct liste_libre **pp_liste_libre=&(p_memoire->p_liste_libre);
struct liste_libre *cel_precedente=NULL, *cel_suivante=NULL, *bus=*pp_liste_libre, *aux;
fprintf(fhistorique," liberer %d %d\n",adresse_libre,taille_libre);
if ((adresse_libre<0) || (adresse_libre+taille_libre>p_memoire->taille_memoire))
{
fprintf(fhistorique," liberer : intervalle invalide ?!\n");
return(-1);
}
/* Recherche des cellules entourant la zone a liberer */
while ((bus!=NULL) && (bus->bloc.adresse<adresse_libre))
{
cel_precedente=bus;
bus=bus->p_suivant;
}
cel_suivante=bus;
if ((cel_precedente!=NULL) && (adresse_libre<cel_precedente->bloc.adresse+cel_precedente->bloc.taille))
{
fprintf(fhistorique," liberer : zone deja libre ?!\n");
return(-1);
}
if ((cel_suivante!=NULL) && (adresse_libre+taille_libre>cel_suivante->bloc.adresse))
{
fprintf(fhistorique," liberer : zone deja libre ?!\n");
return(-1);
}
if ((cel_precedente!=NULL) && (cel_suivante!=NULL) && (cel_suivante->bloc.adresse==cel_precedente->bloc.adresse+cel_precedente->bloc.taille+taille_libre))
{
cel_precedente->p_suivant=cel_suivante->p_suivant;
cel_precedente->bloc.taille+=taille_libre+cel_suivante->bloc.taille;
free(cel_suivante);
cpt_free++;
fprintf(fhistorique," liberer : fusion de 3 zones\n");
return(0);
}
if ((cel_precedente!=NULL) && (adresse_libre==cel_precedente->bloc.adresse+cel_precedente->bloc.taille))
{
cel_precedente->bloc.taille+=taille_libre;
fprintf(fhistorique," liberer : fusion avec la cellule precedente\n");
return(0);
}
if ((cel_suivante!=NULL) && (cel_suivante->bloc.adresse==adresse_libre+taille_libre))
{
cel_suivante->bloc.adresse-=taille_libre;
cel_suivante->bloc.taille+=taille_libre;
fprintf(fhistorique," liberer : fusion avec la cellule suivante\n");
return(0);
}
aux=malloc(sizeof(struct liste_libre));
if (aux==NULL)
{
fprintf(fhistorique," liberer : erreur de malloc !\n");
return(-1);
}
cpt_malloc++;
aux->bloc.adresse=adresse_libre;
aux->bloc.taille=taille_libre;
aux->p_suivant=cel_suivante;
if (cel_precedente==NULL) *pp_liste_libre=aux;
else cel_precedente->p_suivant=aux;
fprintf(fhistorique," liberer : nouvelle cellule inseree\n");
return(0);
}
int allouer_tas(char identite_tas[], int taille_tas, struct memoire *p_memoire)
/* Ajoute un tas de nom identite_tas et de taille taille_tas
Retourne -1 en cas d'erreur, 0 sinon */
{
struct liste_tas **pp_liste_tas=&(p_memoire->p_liste_tas);
struct liste_tas *aux;
int i;
fprintf(fhistorique," allouer_tas %s %d\n",identite_tas,taille_tas);
if (existe_tas(identite_tas,*pp_liste_tas)!=NULL)
{
fprintf(fhistorique," allouer_tas : tas deja existant !\n");
return(-1);
}
aux=malloc(sizeof(struct liste_tas));
if (aux==NULL)
{
fprintf(fhistorique," allouer_tas : erreur de malloc !\n");
return(-1);
}
cpt_malloc++;
aux->tas.taille=taille_tas;
strcpy(aux->tas.ident,identite_tas);
aux->tas.compteur_references=0;
for (i=0;i<MAX_REF;i++) aux->tas.liste_ident[i][0]='\0';
aux->tas.drapeau='B';
if ((aux->tas.adresse=allouer(taille_tas,p_memoire))==-1)
{
free(aux);
cpt_free++;
fprintf(fhistorique," allouer_tas : erreur de allouer !\n");
return(-1);
}
aux->p_suivant=*pp_liste_tas;
*pp_liste_tas=aux;
return(aux->tas.adresse);
}
int liberer_tas(char identite_tas[], struct memoire *p_memoire)
/* Libere le tas de nom identite_tas
Retourne -1 en cas d'erreur, 0 sinon */
{
struct liste_tas **pp_liste_tas=&(p_memoire->p_liste_tas);
struct liste_tas *bus=*pp_liste_tas,*reference,*precedent=NULL;
int i;
fprintf(fhistorique," liberer_tas %s\n",identite_tas);
while ((bus!=NULL) && (strcmp(identite_tas,bus->tas.ident)!=0))
{
precedent=bus;
bus=bus->p_suivant;
}
if (bus==NULL)
{
fprintf(fhistorique," liberer_tas : tas inexistant !\n");
return(-1);
}
if (bus->tas.compteur_references>0)
{
fprintf(fhistorique," liberer_tas : tas reference !\n");
return(-1);
}
if (liberer(bus->tas.adresse,bus->tas.taille,p_memoire)!=0)
{
fprintf(fhistorique," liberer_tas : erreur de liberer\n");
return(-1);
}
for (i=0;i<MAX_REF;i++)
if (bus->tas.liste_ident[i][0]!='\0')
{
reference=existe_tas(bus->tas.liste_ident[i],*pp_liste_tas);
if (reference==NULL)
fprintf(fhistorique," liberer_tas : tas reference a disparu ?!\n");
else reference->tas.compteur_references--;
}
if (precedent==NULL) *pp_liste_tas=bus->p_suivant;
else precedent->p_suivant=bus->p_suivant;
free(bus);
cpt_free++;
return(0);
}
int ajouter_programme(char ident[], struct memoire *p_memoire)
/* Ajoute le programme de nom ident
Retourne -1 en cas d'erreur, 0 sinon */
{
struct liste_tas *p_liste_tas=p_memoire->p_liste_tas;
struct programme **pp_liste_programmes=&(p_memoire->p_liste_programmes);
struct programme *aux,*bus_prog=*pp_liste_programmes;
struct liste_tas *p_tas;
fprintf(fhistorique," ajouter_programme %s\n",ident);
p_tas=existe_tas(ident,p_liste_tas);
if (p_tas==NULL)
{
fprintf(fhistorique," ajouter_programme : tas inexistant !\n");
return(-1);
}
while (bus_prog!=NULL)
{
if (strcmp(ident,bus_prog->ident)==0)
{
fprintf(fhistorique," ajouter_programme : programme deja existant !\n");
return(-1);
}
bus_prog=bus_prog->p_suivant;
}
aux=malloc(sizeof(struct programme));
if (aux==NULL)
{
fprintf(fhistorique," ajouter_programme : erreur de malloc !\n");
return(-1);
}
cpt_malloc++;
strcpy(aux->ident,ident);
aux->p_suivant=*pp_liste_programmes;
p_tas->tas.compteur_references++;
*pp_liste_programmes=aux;
return(0);
}
int supprimer_programme(char ident[], struct memoire *p_memoire)
/* Supprime le programme de nom ident
Retourne -1 en cas d'erreur, 0 sinon */
{
struct liste_tas *p_liste_tas=p_memoire->p_liste_tas;
struct programme **pp_liste_programmes=&(p_memoire->p_liste_programmes);
struct programme *precedent=NULL,*bus_prog=*pp_liste_programmes;
struct liste_tas *p_tas;
fprintf(fhistorique," supprimer_programme %s\n",ident);
while ((bus_prog!=NULL) && (strcmp(ident,bus_prog->ident)!=0))
{
precedent=bus_prog;
bus_prog=bus_prog->p_suivant;
}
if (bus_prog==NULL)
{
fprintf(fhistorique," supprimer_programme : programme inexistant !\n");
return(-1);
}
if (precedent==NULL) *pp_liste_programmes=bus_prog->p_suivant;
else precedent->p_suivant=bus_prog->p_suivant;
free(bus_prog);
cpt_free++;
p_tas=existe_tas(ident,p_liste_tas);
if (p_tas==NULL)
{
fprintf(fhistorique," supprimer_programme : le tas a disparu !?\n");
return(-1);
}
p_tas->tas.compteur_references--;
return(0);
}
int ajouter_lien(char tas_referencant[], char tas_reference[], struct memoire *p_memoire)
/* Ajoute un lien de tas_referencant vers tas_reference
Retourne -1 en cas d'echec, 0 sinon */
{
struct liste_tas *p_liste_tas=p_memoire->p_liste_tas;
struct liste_tas *referencant,*reference;
int i=0;
fprintf(fhistorique," ajouter_lien %s %s\n",tas_referencant,tas_reference);
referencant=existe_tas(tas_referencant,p_liste_tas);
if (referencant==NULL)
{
fprintf(fhistorique," ajouter_lien : tas_referencant inexistant !\n");
return(-1);
}
reference=existe_tas(tas_reference,p_liste_tas);
if (reference==NULL)
{
fprintf(fhistorique," ajouter_lien : tas_reference inexistant !\n");
return(-1);
}
while ((i<MAX_REF) && (referencant->tas.liste_ident[i][0]!='\0')) i++;
if (i==MAX_REF)
{
fprintf(fhistorique," ajouter_lien : maximum de liens atteint !\n");
return(-1);
}
strcpy(referencant->tas.liste_ident[i],tas_reference);
reference->tas.compteur_references++;
return(0);
}
int supprimer_lien(char tas_referencant[], char tas_reference[], struct memoire *p_memoire)
/* Supprime le lien de tas_referencant vers tas_reference
Retourne -1 en cas d'echec, 0 sinon */
{
struct liste_tas *p_liste_tas=p_memoire->p_liste_tas;
struct liste_tas *referencant,*reference;
int i=0;
fprintf(fhistorique," supprimer_lien %s %s\n",tas_referencant,tas_reference);
referencant=existe_tas(tas_referencant,p_liste_tas);
if (referencant==NULL)
{
fprintf(fhistorique," supprimer_lien : tas_referencant inexistant !\n");
return(-1);
}
reference=existe_tas(tas_reference,p_liste_tas);
if (reference==NULL)
{
fprintf(fhistorique," supprimer_lien : tas_reference inexistant !\n");
return(-1);
}
while ((i<MAX_REF) && (strcmp(referencant->tas.liste_ident[i],tas_reference))) i++;
if (i==MAX_REF)
{
fprintf(fhistorique," supprimer_lien : lien inexistant !\n");
return(-1);
}
referencant->tas.liste_ident[i][0]='\0';
reference->tas.compteur_references--;
return(0);
}
int ramasse_miettes_compteurs(struct memoire *p_memoire)
/* Libere les tas dont le compteur de reference est a zero
Retoure -1 si aucun tas n'a ete libere, 0 sinon */
{
struct liste_tas **pp_liste_tas=&(p_memoire->p_liste_tas);
struct liste_tas *bus,*aux;
int n=0,compteur_miettes;
fprintf(fhistorique," ramasse_miettes_compteurs\n");
do
{
compteur_miettes=0;
bus=*pp_liste_tas;
while (bus!=NULL)
{
aux=bus->p_suivant;
if (bus->tas.compteur_references==0)
if (liberer_tas(bus->tas.ident,p_memoire)==0) compteur_miettes++;
bus=aux;
}
n+=compteur_miettes;
} while (compteur_miettes>0);
fprintf(fhistorique," ramasse_miettes_compteurs : %d tas ramasse(s)\n",n);
if (n==0) return(-1); else return(0);
}
int marquage(struct liste_tas *p_liste_tas, struct programme *p_liste_programmes)
/* Marque les tas accessibles depuis les programmes
Retourne -1 en cas d'erreur, 0 sinon */
{
struct programme *bus_prog=p_liste_programmes;
struct liste_tas *bus_tas, *aux;
int compteur_marquage,i;
fprintf(fhistorique," marquage\n");
if (p_liste_programmes==NULL) return(0);
while (bus_prog!=NULL)
{
aux=existe_tas(bus_prog->ident,p_liste_tas);
if (aux==NULL)
{
fprintf(fhistorique," marquage : le tas a disparu !?\n");
return(-1);
}
aux->tas.drapeau='P';
fprintf(fhistorique," marquage : tas %s marque\n",aux->tas.ident);
bus_prog=bus_prog->p_suivant;
}
do
{
compteur_marquage=0;
bus_tas=p_liste_tas;
while (bus_tas!=NULL)
{
if (bus_tas->tas.drapeau=='P')
{
for (i=0;i<MAX_REF;i++)
if (bus_tas->tas.liste_ident[i][0]!='\0')
{
aux=existe_tas(bus_tas->tas.liste_ident[i],p_liste_tas);
if (aux==NULL)
{
fprintf(fhistorique," marquage : le tas reference a disparu !?\n");
return(-1);
}
if (aux->tas.drapeau!='N')
{
aux->tas.drapeau='P';
fprintf(fhistorique," marquage : tas %s marque\n",aux->tas.ident);
compteur_marquage++;
}
}
bus_tas->tas.drapeau='N';
}
bus_tas=bus_tas->p_suivant;
}
}
while (compteur_marquage>0);
return(0);
}
int balayage(struct memoire *p_memoire)
/* Libere les tas non marques
Retoure -1 si aucun tas n'a ete libere, 0 sinon */
{
struct liste_tas **pp_liste_tas=&(p_memoire->p_liste_tas);
struct liste_tas *bus=*pp_liste_tas, *aux;
int n=0,i;
fprintf(fhistorique," balayage\n");
while (bus!=NULL)
{
aux=bus->p_suivant;
if (bus->tas.drapeau=='B')
{
bus->tas.compteur_references=0;
for (i=0;i<MAX_REF;i++) bus->tas.liste_ident[i][0]='\0';
if (liberer_tas(bus->tas.ident,p_memoire)==0) n++;
}
else bus->tas.drapeau='B';
bus=aux;
}
fprintf(fhistorique," balayage : %d tas balaye(s)\n",n);
if (n==0) return(-1); else return(0);
}
int ramasse_miettes_marquage_balayage(struct memoire *p_memoire)
/* Libere les tas non accessibles depuis les programmes
Retourne -1 en cas d'erreur, 0 sinon */
{
struct liste_tas *p_liste_tas=p_memoire->p_liste_tas;
struct programme *p_liste_programmes=p_memoire->p_liste_programmes;
fprintf(fhistorique," ramasse_miettes_marquage_balayage\n");
if (marquage(p_liste_tas,p_liste_programmes)==-1)
{
fprintf(fhistorique," ramasse_miettes_marquage_balayage : erreur de marquage ?!\n");
return(-1);
}
if (balayage(p_memoire)==-1)
{
fprintf(fhistorique," ramasse_miettes_marquage_balayage : aucun tas balaye\n");
return(-1);
}
return(0);
}