Files
FAT-Allocator/allocator/freelist/freelist.c

166 lines
3.9 KiB
C

#include "freelist_allocator.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
char *small_freelist = NULL;
char *medium_freelist = NULL;
char *large_freelist = NULL;
void initialize(unsigned int size_in_pages)
{
/* request memory for our allocation buffer
* NB mmap min bounds for capability is 1 page (4K)
*/
size_t bytes_to_allocate = size_in_pages * BYTES_IN_PAGE;
char *res =
mmap(NULL, bytes_to_allocate, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (res == MAP_FAILED)
{
perror("error in initial mem allocation");
exit(-1);
}
// put in linked list pointers and
// stick into the large freelist
// give this space to the large freelist ...
large_freelist = insert_linked_list_pointers(LARGE, bytes_to_allocate, res, large_freelist);
return;
}
char *insert_linked_list_pointers(size_t cell_size, size_t limit, char *start, char *freelist)
{
char *curr = start;
char *next = curr + cell_size;
char *max = start + limit;
// ensure next ptr will fit into cell
assert(sizeof(void *) <= cell_size);
while (next < max)
{
((char **) curr)[0] = next;
curr = next;
next = curr + cell_size;
}
// at the end, concatenate this newly formed
// list with existing freelist
((char **) curr)[0] = freelist;
return start;
}
char *alloc(size_t bytes)
{
size_t size;
char *freelist_to_use = NULL;
char *ret = NULL; // ptr to return
// work out which freelist to use
if (bytes <= SMALL)
{
size = SMALL;
freelist_to_use = small_freelist;
}
else if (bytes <= MEDIUM)
{
size = MEDIUM;
freelist_to_use = medium_freelist;
}
else
{
size = LARGE;
freelist_to_use = large_freelist;
}
if (freelist_to_use == NULL)
{
// fixup freelist (if no available mem there)
char *new_space = NULL;
switch (size)
{
case SMALL:
new_space = alloc(MEDIUM);
if (new_space != NULL)
{
small_freelist =
insert_linked_list_pointers(SMALL, MEDIUM, new_space, small_freelist);
freelist_to_use = small_freelist;
// now we have replenished space...
}
break;
case MEDIUM:
new_space = alloc(LARGE);
if (new_space != NULL)
{
medium_freelist =
insert_linked_list_pointers(MEDIUM, LARGE, new_space, medium_freelist);
freelist_to_use = medium_freelist;
}
break;
default:
// stuck! no more mem!
// we will return NULL
break;
}
}
// pop from head of freelist (if there's anything there)
if (freelist_to_use != NULL)
{
char *head = freelist_to_use;
char *tail = ((char **) head)[0];
switch (size)
{
case SMALL:
small_freelist = tail;
break;
case MEDIUM:
medium_freelist = tail;
break;
default:
large_freelist = tail;
break;
}
ret = head;
SET_SIZE(ret, size);
}
return ret;
}
void dealloc(void *buffer)
{
// work out the size of the buffer
size_t size;
char *freelist;
size = GET_SIZE(buffer);
// then prepend it to the appropriate freelist
switch (size)
{
case SMALL:
small_freelist = cons_onto_freelist(buffer, small_freelist);
break;
case MEDIUM:
medium_freelist = cons_onto_freelist(buffer, medium_freelist);
break;
default:
large_freelist = cons_onto_freelist(buffer, large_freelist);
break;
}
return;
}
char *cons_onto_freelist(char *cell, char *freelist)
{
((char **) cell)[0] = freelist;
return cell;
}