Commit 7ea69169 authored by Robin Delbos's avatar Robin Delbos
Browse files

Test

parents
common.o: common.c mem.h common.h
mem.o: mem.c mem.h common.h
CC=gcc
# uncomment to compile in 32bits mode (require gcc-*-multilib packages
# on Debian/Ubuntu)
#HOST32= -m32
CFLAGS+= $(HOST32) -Wall -Werror -std=c99 -g -DMEMORY_SIZE=128000
CFLAGS+= -DDEBUG
# pour tester avec ls
CFLAGS+= -fPIC
LDFLAGS= $(HOST32)
TESTS+=test_init
PROGRAMS=memshell $(TESTS)
.PHONY: clean all test_ls
all: $(PROGRAMS)
for file in $(TESTS);do ./$$file; done
%.o: %.c
$(CC) -c $(CFLAGS) -MMD -MF .$@.deps -o $@ $<
# dépendences des binaires
$(PROGRAMS) libmalloc.so: %: mem.o common.o
-include $(wildcard .*.deps)
# seconde partie du sujet
libmalloc.so: malloc_stub.o
$(CC) -shared -Wl,-soname,$@ $^ -o $@
test_ls: libmalloc.so
LD_PRELOAD=./libmalloc.so ls
# nettoyage
clean:
$(RM) *.o $(PROGRAMS) libmalloc.so .*.deps
Ce package contient :
- un petit programme de test interactif de l'allocateur qui devra être implémenté dans mem.c : memshell
- un petit programme contenant un test simple de l'initialisation de l'allocateur qui devra être implémenté dans mem.c : test_init
- un Makefile vous permettant de compiler tout ces petits programmes et de tester votre allocateur avec une appli réelle (make test_ls)
ATTENTION: sans implémentation correcte du début de l'allocateur, test_init boucle indéfiniment.
File added
#include "mem.h"
#include "common.h"
#include <assert.h>
#include <stdio.h>
#ifndef MEMORY_SIZE
#define MEMORY_SIZE 8192
#endif
static char memory[MEMORY_SIZE];
void *get_memory_adr() {
return memory;
}
size_t get_memory_size() {
return MEMORY_SIZE;
}
void *alloc_max(size_t estimate) {
void *result;
static size_t last = 0;
while ((result = mem_alloc(estimate)) == NULL) {
estimate--;
}
debug("Alloced %zu bytes at %p\n", estimate, result);
if (last) {
// Idempotence test
assert(estimate == last);
} else
last = estimate;
return result;
}
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdlib.h>
#ifdef DEBUG
# include <stdio.h>
# define debug(...) ((void)fprintf(stderr, __VA_ARGS__))
#else
# define debug(...) ((void)0)
#endif
void *get_memory_adr();
size_t get_memory_size();
void *alloc_max(size_t estimate);
#endif
File added
#include "mem.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
static __thread int in_lib=0;
#define dprintf(args...) \
do { \
if (!in_lib) { \
in_lib=1; \
fprintf(stderr, args); \
in_lib=0; \
} \
} while (0)
static
void init() {
static int first=1;
if (first) {
mem_init(get_memory_adr(), get_memory_size());
first = 0;
}
}
void *malloc(size_t s) {
void *result;
init();
dprintf("Allocation de %lu octets...", (unsigned long) s);
result = mem_alloc(s);
if (!result)
dprintf(" Alloc FAILED !!");
else
dprintf(" %lx\n", (unsigned long) result);
return result;
}
void *calloc(size_t count, size_t size) {
int i;
char *p;
size_t s = count*size;
init();
dprintf("Allocation de %zu octets\n", s);
p = mem_alloc(s);
if (!p)
dprintf(" Alloc FAILED !!");
if (p)
for (i=0; i<s; i++)
p[i] = 0;
return p;
}
void *realloc(void *ptr, size_t size) {
size_t s;
char *result;
init();
dprintf("Reallocation de la zone en %lx\n", (unsigned long) ptr);
if (!ptr) {
dprintf(" Realloc of NULL pointer\n");
return mem_alloc(size);
}
if (mem_get_size(ptr) >= size) {
dprintf(" Useless realloc\n");
return ptr;
}
result = mem_alloc(size);
if (!result) {
dprintf(" Realloc FAILED\n");
return NULL;
}
for (s = 0; s<mem_get_size(ptr); s++)
result[s] = ((char *) ptr)[s];
mem_free(ptr);
dprintf(" Realloc ok\n");
return result;
}
void free(void *ptr) {
init();
if (ptr) {
dprintf("Liberation de la zone en %lx\n", (unsigned long) ptr);
mem_free(ptr);
} else {
dprintf("Liberation de la zone NULL\n");
}
}
#ifndef __MALLOC_STUB_H__
#define __MALLOC_STUB_H__
#include <stdlib.h>
void *malloc(size_t s);
void *calloc(size_t count, size_t size);
void *realloc(void *ptr, size_t size);
void free(void *ptr);
#endif
#include "mem.h"
#include "common.h"
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <stdbool.h>
// constante définie dans gcc seulement
#ifdef __BIGGEST_ALIGNMENT__
#define ALIGNMENT __BIGGEST_ALIGNMENT__
#else
#define ALIGNMENT 16
#endif
#define ALIGN(val,align)\
(((__intptr_t)(val) + ((align) - 1))&~((align) - 1))
/* zone libre et zone occupée */
struct fb {
size_t size;
bool occupied; // Vaut true si c'est coccupé et false si c'est libre
struct fb* next;
struct fb* predecessor;
};
/* structure globale */
typedef struct {
size_t size;
size_t meta_size; // taille des meta données
void *adresse;
}memoire;
memoire mem;
void mem_init(void* memoire, size_t taille) {
assert(memoire == get_memory_adr());
assert(taille == get_memory_size());
mem.adresse = memoire; //init de la structure globale mem
mem.size = taille;
mem.meta_size = sizeof(struct fb);
mem.meta_size = ALIGN(mem.meta_size, ALIGNMENT);
printf("meta_size = %ld \n",mem.meta_size);
struct fb *first_fb = (struct fb*)mem.adresse; //Première zone libre
first_fb->size = mem.size - mem.meta_size;
first_fb->occupied = 0;
first_fb->next = NULL;
first_fb->predecessor = NULL;
mem_fit(&mem_fit_first); // Choix de la méthode pour remplier la zone
}
void mem_show(void (*print)(void *, size_t, int)) {
void *current = mem.adresse;
while (current != NULL) {
struct fb *first_fb = (struct fb*)current;
if(first_fb->occupied == 1)
print(current, first_fb->size + mem.meta_size, !first_fb->occupied); //si c'est une zo, on renvoie le info de la zone sinon on ne renvoi rien
current = first_fb->next;
}
}
static mem_fit_function_t *mem_fit_fn;
void mem_fit(mem_fit_function_t *f) {
mem_fit_fn=f;
}
void *mem_alloc(size_t taille) {
__attribute__((unused)) // juste pour que gcc compile ce squelette avec -Werror
struct fb *zone=mem_fit_fn( (struct fb*)mem.adresse, taille); //Recherche d'une zone libre
taille = ALIGN(taille,ALIGNMENT);
if(taille < zone->size){ // Si la taille = la taille de la zone alors elle devient une zo sinon on créé une autre zone libre
void *adresse = (void*)zone + taille + mem.meta_size ;
struct fb *zone_libre = (struct fb*)adresse;
zone_libre->size = zone->size - taille - mem.meta_size;
zone_libre->occupied = 0;
zone_libre->predecessor = zone;
zone_libre->next = zone->next;
zone->next = zone_libre;
}
zone->size = taille;
zone->occupied = 1;
return zone;
}
void mem_free(void* adresse) { //on a changé le nom de l'argument car mem été déjà prit
struct fb *zone = (struct fb*)adresse;
struct fb *predecessor= zone->predecessor;
struct fb *next = zone->next;
if ((predecessor == NULL || predecessor->occupied==1)&&(next == NULL || next->occupied==1)) // Cas où predecessor et next sont des zo ou NULL (4 cas possibles)
zone->occupied = 0;
else if ( predecessor != NULL && predecessor->occupied == 0 ){ //Cas où predecessor est une zone libre
predecessor->next = zone->next;
predecessor->size = predecessor->size + mem.meta_size + zone->size ;
if( next != NULL )
next->predecessor = predecessor;
if(next != NULL && next->occupied == 0)
mem_free((void*)predecessor);
}
else if (next != NULL && next->occupied == 0){ //Cas où next est une zone libre
zone->next = next->next;
zone->size = zone->size + mem.meta_size + next->size;
zone->occupied = 0;
if( predecessor != NULL)
predecessor->next = zone;
}
}
struct fb* mem_fit_first(struct fb *list, size_t size) { //retourne l’adresse du premier bloc libre de taille supérieure ou égale à size présent dans la liste de blocs libre dont l’adresse est list.
if (size > mem.size - mem.meta_size){
printf("ERROR\n");
return NULL;
}
struct fb *current = list;
while( ((void *)current) < (mem.adresse + mem.size) ){ // tant qu'on ne dépasse pas la fin de la memoire
if(current->occupied == 0)
if(current->size >= size + mem.meta_size) // Il faut laisser de la place pour créer les meta de la zone libre
return current;
current = current->next ;
}
printf("Error\n");
return NULL;
}
/* Fonction à faire dans un second temps
* - utilisée par realloc() dans malloc_stub.c
* - nécessaire pour remplacer l'allocateur de la libc
* - donc nécessaire pour 'make test_ls'
* Lire malloc_stub.c pour comprendre son utilisation
* (ou en discuter avec l'enseignant)
*/
size_t mem_get_size(void *adresse) {
/* zone est une adresse qui a été retournée par mem_alloc() */
struct fb *zone = (struct fb*)adresse;
/* la valeur retournée doit être la taille maximale que
* l'utilisateur peut utiliser dans cette zone */
return zone->size;
}
/* Fonctions facultatives
* autres stratégies d'allocation
*/
struct fb* mem_fit_best(struct fb *list, size_t size) {
return NULL;
}
struct fb* mem_fit_worst(struct fb *list, size_t size) {
return NULL;
}
#ifndef __MEM_H
#define __MEM_H
#include <stddef.h>
struct fb;
/* fonctions principales de l'allocateur */
void mem_init(void* mem, size_t taille);
void* mem_alloc(size_t size);
void mem_free(void *ptr);
void* mem_realloc(void *old, size_t new_size);
/* Itération sur le contenu de l'allocateur */
/* nécessaire pour le mem_shell */
void mem_show(void (*print)(void *adr, size_t size, int free));
/* Choix de la stratégie et strategies usuelles */
/* Si vous avez le temps... */
typedef struct fb* (mem_fit_function_t)(struct fb*, size_t);
void mem_fit(mem_fit_function_t*);
mem_fit_function_t mem_fit_first;
mem_fit_function_t mem_fit_worst;
mem_fit_function_t mem_fit_best;
#endif
File added
File added
#include "mem.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#define TAILLE_BUFFER 128
void aide()
{
fprintf(stderr,"Aide :\n");
fprintf(stderr,"Saisir l'une des commandes suivantes\n");
fprintf(stderr,"\n");
fprintf(stderr,"a taille : allouer un bloc de la taille souhaitee\n");
fprintf(stderr,"l adresse : librer un bloc alloue precedemment\n");
fprintf(stderr,"i : afficher la liste des emplacements memoire "
"inocupes\n");
fprintf(stderr,"o : afficher la liste des emplacements memoire "
"occupes\n");
fprintf(stderr,"M : afficher la liste de tous les emplacements "
"memoire (libres et occupes)\n");
fprintf(stderr,"m : afficher le dump de la memoire\n");
fprintf(stderr,"h : afficher cette aide\n");
fprintf(stderr,"q : quitter ce programme\n");
fprintf(stderr,"\n");
}
void afficher_zone(void *adresse, size_t taille, int free)
{
printf("Zone %s, Adresse : %lu, Taille : %lu\n", free?"libre":"occupee",
adresse - get_memory_adr(), (unsigned long) taille);
}
void afficher_zone_libre(void *adresse, size_t taille, int free)
{
if (free)
afficher_zone(adresse, taille, 1);
}
void afficher_zone_occupee(void *adresse, size_t taille, int free)
{
if (!free)
afficher_zone(adresse, taille, 0);
}
int main()
{
char buffer[TAILLE_BUFFER];
char commande;
char *adresse;
void *ptr;
int offset;
int taille, i;
aide();
mem_init(get_memory_adr(),get_memory_size());
while (1) {
printf("? ");
fflush(stdout);
commande = getchar();
switch (commande) {
case 'a':
scanf ("%d",&taille);
ptr = mem_alloc(taille);
if (ptr == NULL)
printf("Echec de l'allocation\n");
else
printf("Memoire allouee en %d\n", (int) (ptr-get_memory_adr()));
break;
case 'l':
scanf ("%d", &offset);
mem_free(get_memory_adr()+offset);
printf("Memoire liberee\n");
break;
case 'i':
mem_show(afficher_zone_libre);
break;
case 'o':
mem_show(afficher_zone_occupee);
break;
case 'M':
mem_show(afficher_zone);
break;
case 'm':
printf("[ ");
adresse = get_memory_adr();
for (i=0; i<get_memory_size(); i++)
printf("%d ", adresse[i]);
printf("]\n");
break;
case 'h':
aide();
break;
case 'q':
exit(0);
default:
fprintf(stderr,"Commande inconnue !\n");
}
/* vide ce qu'il reste de la ligne dans le buffer d'entree */
fgets(buffer,TAILLE_BUFFER,stdin);
}
return 0;
}
File added
#include "mem.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define NB_TESTS 10
int main(int argc, char *argv[]) {
fprintf(stderr, "Test réalisant de multiples fois une initialisation suivie d'une alloc max.\n"
"Définir DEBUG à la compilation pour avoir une sortie un peu plus verbeuse."
"\n");
for (int i=0; i<NB_TESTS; i++) {
debug("Initializing memory\n");
mem_init(get_memory_adr(), get_memory_size());
alloc_max(get_memory_size());
}
// TEST OK
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment