This commit is contained in:
Guillem George 2025-11-07 20:29:21 +01:00
parent 06fac933c2
commit b4f942f678
6 changed files with 174 additions and 37 deletions

View file

@ -1,10 +1,10 @@
CC=gcc CC=gcc
CFLAGS=-std=c99 -pedantic -Werror -Wall -Wextra -Wvla -fvisibility=hidden -fPIC CFLAGS=-std=c99 -pedantic -Werror -Wall -Wextra -Wvla -fvisibility=hidden -fPIC
CPPFLAGS=D_DEFAULT_SOURCE CPPFLAGS= -D_DEFAULT_SOURCE
LDFLAGS= -shared -Wl --no-undefined LDFLAGS= -shared -Wl --no-undefined
SRCS= SRCS=src/malloc.c src/helpers/helpers.c src/helpers/allocate.c
OBJS=${SRC:.c=.o} OBJS=${SRCS:.c=.o}
TARGET=libmalloc.so TARGET=libmalloc.so
library: $(OBJS) library: $(OBJS)

View file

@ -0,0 +1,70 @@
#include "allocate.h"
#include <string.h>
#include <sys/mman.h>
#include "helpers.h"
void *allocate_block(struct bucket *biquette, int block_number)
{
if (block_number == -1)
return NULL;
// Update header
unsigned char byte_mask = 1 << ((block_number % 8) - 1);
biquette->alloc_blk_cnt++;
biquette->free_map[block_number / 8] &= byte_mask;
// Compute block address
return get_block(biquette, block_number);
}
struct bucket *create_bucket(size_t min_alloc_size)
{
// Round up
size_t alloc_size;
if (min_alloc_size > PAGE_SIZE - sizeof(struct bucket))
// Huge page
alloc_size = min_alloc_size;
else
// Regular page
alloc_size = s2p(min_alloc_size);
// Get page
void *page =
mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, -1, 0);
if (page == NULL)
return NULL;
// Init bucket
struct bucket *header = page;
header->block_size = alloc_size;
header->alloc_blk_cnt = 0;
memset(header->free_map, 0, FREE_LIST_SIZE);
return header;
}
void free_block(void *ptr, struct bucket **list)
{
// Compute header location and block number
struct bucket *header = get_page_begin(ptr);
// free in map and update size
int block_number; // ...
unsigned char byte_mask = 1 << ((block_number % 8) - 1);
header->free_map[block_number / 8] &= ~byte_mask;
// Huge page
if (header->block_size > BUCKET_SIZE)
// Delete bucket
header->alloc_blk_cnt = 0;
// free bucket if necessary
if (header->alloc_blk_cnt == 0)
{
bucket_list_remove(list, header);
munmap(ptr, 1);
}
}

View file

@ -0,0 +1,13 @@
#ifndef ALLOCATE_H
#define ALLOCATE_H
#include "helpers.h"
#include <stddef.h>
void *allocate_block(struct bucket *biquette, int block_number);
struct bucket *create_bucket(size_t min_alloc_size);
void bucket_append(struct bucket **head, struct bucket *elt);
void free_block(void *ptr, struct bucket **list);
#endif // ! ALLOCATE_H

View file

@ -1,8 +1,5 @@
#include "helpers.h" #include "helpers.h"
#include <string.h>
#include <sys/mman.h>
// Returns the smallest power of 2 greater or equal to s // Returns the smallest power of 2 greater or equal to s
size_t s2p(size_t s) size_t s2p(size_t s)
{ {
@ -33,44 +30,47 @@ size_t s2p(size_t s)
return n; return n;
} }
void *find_free_block(struct bucket *buck) int find_free_block(struct bucket *buck)
{ {
unsigned maplength = buck->block_size / 8; unsigned maplength = PAGE_SIZE / buck->block_size / 8;
// for each block // for each block
for (unsigned i = 0; i < maplength; i++) for (unsigned i = 0; i < maplength; i++)
{ {
unsigned char map_byte = buck->free_list[i]; unsigned char map_byte = buck->free_map[i];
unsigned char bit = 1; unsigned char bit = 1;
// Test byte // Test byte
for (unsigned j = 0; j < 8; j <<= 1) for (unsigned j = 0; j < 8; j <<= 1)
{ {
if (map_byte & bit) // Test if free if (map_byte & bit) // Test if free
return get_data_begin(buck) + (buck->block_size * (i * 8 + j)); return i * 8 + j;
bit <<= 1; bit <<= 1;
} }
} }
return NULL; return -1;
} }
struct bucket *create_bucket(size_t min_alloc_size) void *get_block(struct bucket *biquette, int block_number)
{ {
// Round up if (block_number == -1)
size_t alloc_size = s2p(min_alloc_size);
// Get page
void *page =
mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, -1, 0);
if (page == NULL)
return NULL; return NULL;
// Init bucket char *data_begin = get_data_begin(biquette);
struct bucket *header = page; return data_begin + (biquette->block_size * (block_number));
header->block_size = alloc_size; }
memset(header->free_list, 0, FREE_LIST_SIZE);
return header; int get_block_number(struct bucket *biquette, void *block)
{
if (block == NULL || biquette == NULL)
return -1;
char *block_nul = block;
void *biquetteounette = biquette;
char *biquette_cherie = biquetteounette;
return (block_nul - biquette_cherie - sizeof(struct bucket))
/ biquette->block_size;
} }
// Gets a bucket with at least a block_size of size // Gets a bucket with at least a block_size of size
@ -99,7 +99,7 @@ void *get_page_begin(void *ptr)
return pointeur_alacon + quelenfer; return pointeur_alacon + quelenfer;
} }
void bucket_append(struct bucket **head, struct bucket *elt) void bucket_list_append(struct bucket **head, struct bucket *elt)
{ {
struct bucket *list_elt = *head; struct bucket *list_elt = *head;
if (list_elt == NULL) if (list_elt == NULL)
@ -114,3 +114,27 @@ void bucket_append(struct bucket **head, struct bucket *elt)
} }
list_elt->next = elt; list_elt->next = elt;
} }
// Removes a bucket from the list pointed by head
void bucket_list_remove(struct bucket **head, struct bucket *elt)
{
struct bucket *list_elt = *head;
if (list_elt == NULL)
return;
if (*head == elt)
{
*head = NULL;
return;
}
while (list_elt->next != NULL)
{
if (list_elt->next == elt)
{
list_elt->next = list_elt->next->next;
return;
}
list_elt = list_elt->next;
}
}

View file

@ -1,7 +1,7 @@
#ifndef HELPERS_H #ifndef HELPERS_H
#define HELPERS_H #define HELPERS_H
// #define PAGE_SIZE (size_t) sysconf(_SC_PAGE_SIZE) // #define PAGE_SIZE sysconf(_SC_PAGE_SIZE)
#define PAGE_SIZE 4096 #define PAGE_SIZE 4096
#define MIN_BLOCK_SIZE 8 #define MIN_BLOCK_SIZE 8
#define FREE_LIST_SIZE PAGE_SIZE / MIN_BLOCK_SIZE / sizeof(unsigned char) #define FREE_LIST_SIZE PAGE_SIZE / MIN_BLOCK_SIZE / sizeof(unsigned char)
@ -13,19 +13,24 @@
struct bucket struct bucket
{ {
unsigned block_size; unsigned block_size;
unsigned char free_list[FREE_LIST_SIZE]; // 4096 / MIN_BLOCK_SIZE / unsigned char free_map[FREE_LIST_SIZE]; // Keeps track of allocations
// sizeof(unsigned char) // If block_size > MIN_BLOCK_SIZE
// It will use a consecutive
// representation
unsigned short alloc_blk_cnt; // Counts the number of allocated blocks
struct bucket *next; struct bucket *next;
size_t checksum; size_t checksum;
}; };
#define BUCKET_SIZE PAGE_SIZE - sizeof(struct bucket)
size_t s2p(size_t n); size_t s2p(size_t n);
void *find_free_block(struct bucket *buck); int find_free_block(struct bucket *buck);
struct bucket *create_bucket(size_t min_alloc_size);
struct bucket *get_bucket(struct bucket *head, size_t size); struct bucket *get_bucket(struct bucket *head, size_t size);
void *get_data_begin(struct bucket *biquette); void *get_data_begin(struct bucket *biquette);
void *get_page_begin(void *ptr); void *get_page_begin(void *ptr);
void bucket_append(struct bucket **head, struct bucket *elt); void *get_block(struct bucket* biquette, int block_number);
void bucket_list_append(struct bucket **head, struct bucket *elt);
void bucket_list_remove(struct bucket **head, struct bucket *elt);
#endif // ! HELPERS_H #endif // ! HELPERS_H

View file

@ -1,5 +1,7 @@
#include <stddef.h> #include <stddef.h>
#include <string.h>
#include "helpers/allocate.h"
#include "helpers/helpers.h" #include "helpers/helpers.h"
struct bucket *head = NULL; struct bucket *head = NULL;
@ -14,14 +16,13 @@ __attribute__((visibility("default"))) void *malloc(size_t size)
while (buck != NULL) while (buck != NULL)
{ {
// Find adequate block // Find adequate block
void *block = find_free_block(buck); int block_number = find_free_block(buck);
if (block != NULL) if (block_number != -1)
return block; return get_block(buck, block_number);
else else
{ {
// No free space -> loop // No free space -> loop
buck = get_bucket(buck->next, size); buck = get_bucket(buck->next, size);
continue;
} }
} }
@ -34,14 +35,38 @@ __attribute__((visibility("default"))) void free(void *ptr)
{ {
if (ptr == NULL) if (ptr == NULL)
return; return;
free_block(ptr, &head);
} }
__attribute__((visibility("default"))) void *realloc(void *ptr, size_t size) __attribute__((visibility("default"))) void *realloc(void *ptr, size_t size)
{ {
if (size == 0)
return NULL;
if (ptr == NULL)
return malloc(size);
struct bucket *header = get_page_begin(ptr);
if (header == NULL)
return NULL; // Shouldn't get here
if (header->block_size >= size)
{
return ptr;
}
else
{
void *new_ptr = malloc(size);
memcpy(new_ptr, ptr, header->block_size);
free(ptr);
return new_ptr;
}
return NULL; return NULL;
} }
__attribute__((visibility("default"))) void *calloc(size_t nmemb, size_t size) __attribute__((visibility("default"))) void *calloc(size_t nmemb, size_t size)
{ {
return NULL; char *res = malloc(nmemb * size);
memset(res, 0, nmemb * size);
return res;
} }