1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
| /* rgn.c --- Routines d'allocation mémoire par régions. */
#include "rgn.h"
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
/* L'allocation de bas niveau se fait avec "mmap":
ptr = mmap (NULL, nbytes,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)
où nbytes doit être un multiple de la taille d'une page, i.e. un multiple
de sysconf(_SC_PAGESIZE). Cette mémoire peut être libérée plus tard
avec "munmap".
Voir "man mmap", "man munmap", et "man sysconf" pour de plus amples
informations. */
/* Type d'un descripteur de région. */
struct rgn {
int unlimited;
int size;
void *start;
void *next;
rgn *linked;
};
rgn *lastpage = NULL;
void new_page()
{
lastpage = mmap(NULL, 4096, PROT_READ | PROT_WRITE , MAP_ANONYMOUS |
MAP_PRIVATE , -1 , 0);
(*lastpage).unlimited = 0;
(*lastpage).size = 4096 - sizeof(rgn);
(*lastpage).start = lastpage;
(*lastpage).next = lastpage + sizeof(rgn);
(*lastpage).linked = NULL;
}
/* Crée une nouvelle région dont la taille maximale est "maxbytes", ou
qui peut grandir sans limite si "maxbytes" est égal à 0. */
rgn *rgn_new (size_t maxbytes)
{
rgn *r;
/*Cas ou nous creons une region de taille illimitee :
On va commencer par allouer une region a une nouvelle page. Si la region
atteint sa taille limite, alors on recreera une nouvelle region dans
rgn_alloc que l'on reliera a la premiere region via le pointeur "linked"*/
if(maxbytes == 0) {
r = mmap(NULL, 4096, PROT_READ | PROT_WRITE , MAP_ANONYMOUS |
MAP_PRIVATE , -1 , 0);
//On test si l'appel a mmap a reussi...
if( r == MAP_FAILED) {
//Si l'allocation a echoue, on imprime un message d'erreur
perror(" Erreur mmap");
}
else {
//Sinon, on cree une region r dans l'espace alloue
(*r).unlimited = 1;
(*r).start = r;
(*r).next = r + sizeof(rgn);
(*r).linked = NULL;
}
}
//Cas ou la taille de la region a allouer est inferieure a la taille d'une
//page :
if(maxbytes <= 4096 && maxbytes != 0) {
// Si la derniere page allouee est egale a NULL :
if(lastpage == NULL) {
// On alloue une nouvelle page entiere:
new_page();
// Et on alloue un espace pour la region a l'interieur de cette page
r = rgn_alloc(lastpage, maxbytes);
// Si l'allocation a echoue
if(r == NULL) {
perror("Allocation failed");
}
//Sinon
else {
(*r).unlimited = 0;
(*r).size = maxbytes;
(*r).start = r;
(*r).next = r + sizeof(rgn);
(*r).linked = NULL;
}
}
//Si la derniere page allouee n'est pas NULL :
else {
//S'il reste assez de place dans la derniere page allouee :
if((*lastpage).size >= maxbytes + sizeof(rgn)) {
r = rgn_alloc(lastpage, maxbytes);
if(r == NULL) { perror("Allocation failed");}
else {
(*lastpage).size = (*lastpage).size - maxbytes - sizeof(rgn);
(*lastpage).next = (*lastpage).next + sizeof(rgn) + maxbytes;
(*r).unlimited = 0;
(*r).size = maxbytes;
(*r).start = r;
(*r).next = r + sizeof(rgn);
(*r).linked = NULL;
}}
//Sinon, on cree une autre page :
else {
// On alloue une nouvelle page entiere:
new_page();
// Et on alloue un espace pour la region a l'interieur de cette page
r = rgn_alloc(lastpage, maxbytes);
// Si l'allocation a echoue
if(r != NULL) { perror("Allocation failed");}
//Sinon
else {
(*r).unlimited = 0;
(*r).size = maxbytes;
(*r).start = r;
(*r).next = r + sizeof(rgn);
(*r).linked = NULL;
}
}
}
}
return r;
}
/* Alloue un espace de "nbytes" dans la région "r" et renvoie son adresse,
ou NULL si l'allocation échoue. */
void *rgn_alloc (rgn *r, size_t nbytes)
{
rgn *r2 = NULL;
r2 = mmap((*r).next, nbytes, PROT_READ | PROT_WRITE , MAP_ANONYMOUS |
MAP_PRIVATE , -1 , 0);
if(r2 != NULL) {
(*r).size = (*r).size - nbytes - sizeof(rgn);
(*r).next = (*r).size + nbytes + sizeof(rgn);
}
return r2;
}
/* Libère l'espace occupé par la région "r". */
void rgn_free (rgn *r)
{
munmap(r, (*r).size + sizeof(rgn));
}
#if 0
/* On put implanter "malloc" au-dessus de nos régions. */
void *malloc (size_t nbytes)
{
rgn *r = rgn_new (nbytes + sizeof (rgn*));
rgn **x = rgn_alloc (r, nbytes + sizeof (rgn*));
*x = r;
return x+1;
}
void free (void *ptr)
{
rgn **x = ptr;
rgn_free (x[-1]);
}
#endif
int main()
{
new_page();
rgn *r;
r = rgn_new(45);
printf("%i %i %p %p %p \n", (*r).unlimited, (*r).size, (*r).start , (*r).next ,
(*r).linked);
return 0;
}
/* arch-tag: 64fdb756-d391-4f17-98b7-a5ecff6b652f */ |
Partager