copy on git

This commit is contained in:
Thomas Rieg 2025-11-28 19:50:58 +01:00
commit 42653de246
205 changed files with 7459 additions and 0 deletions

85
srcs/bonus_utils.c Normal file
View file

@ -0,0 +1,85 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* bonus_utils.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: thrieg < thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/11/28 16:42:13 by thrieg #+# #+# */
/* Updated: 2025/11/28 18:25:49 by thrieg ### ########.fr */
/* */
/* ************************************************************************** */
#include "../includes/ft_malloc.h"
#include "../libft/ft_printf/ft_printf.h"
// bytes_per_line has to be a power of 2
static void hexdump_block(void *addr, size_t size, size_t bytes_per_Line)
{
unsigned char *p = (unsigned char *)addr;
uintptr_t start = (uintptr_t)p;
uintptr_t end = start + size;
// align down to bytes_per_Line bytes
uintptr_t line_start = start & ~(uintptr_t)(bytes_per_Line - 1);
while (line_start < end)
{
ft_printf("%p: ", (void *)line_start);
for (size_t i = 0; i < bytes_per_Line; ++i)
{
uintptr_t pos = line_start + (uintptr_t)i;
if (pos < start || pos >= end)
{
// outside the block; print spaces to keep alignment
ft_printf(" ");
}
else
{
unsigned char byte = *(unsigned char *)pos;
ft_printf("%02x ", (unsigned int)byte);
}
}
ft_printf("\n");
line_start += bytes_per_Line;
}
}
void print_zone(t_zone *zone, bool hexdump_free_zones)
{
ft_printf("--------------------------------\n");
ft_printf("new %s zone:\n", zone->type == E_TINY ? "tiny" : (zone->type == E_SMALL ? "small" : "large"));
ft_printf("size: %u\n", (unsigned int)zone->size);
ft_printf("--------------------------------\n");
char *zone_end = (char *)zone + zone->size;
t_header *header = (t_header *)(zone + 1);
while ((char *)header + sizeof(t_header) <= zone_end)
{
ft_printf("--------------------------------\n");
ft_printf("new %s header:\n", header->occupied ? "allocated" : "free");
ft_printf("size: %u\n", (unsigned int)header->size);
ft_printf("--------------------------------\n");
if (header->occupied || hexdump_free_zones)
hexdump_block(header + 1, header->size, 16);
header = (t_header *)((char *)(header + 1) + header->size);
}
}
void print_all_zones(t_zone *first_zone, bool hexdump_free_zones)
{
while (first_zone)
{
print_zone(first_zone, hexdump_free_zones);
first_zone = first_zone->next;
}
}
void show_alloc_mem_ex(bool hexdump_free_zones)
{
print_all_zones(g_state.tiny_zone, hexdump_free_zones);
print_all_zones(g_state.small_zone, hexdump_free_zones);
print_all_zones(g_state.large_zone, hexdump_free_zones);
}

BIN
srcs/bonus_utils.o Normal file

Binary file not shown.

29
srcs/ft_calloc.c Normal file
View file

@ -0,0 +1,29 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_calloc.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: thrieg < thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/11/25 11:47:16 by thrieg #+# #+# */
/* Updated: 2025/11/28 16:41:16 by thrieg ### ########.fr */
/* */
/* ************************************************************************** */
#include "../includes/ft_malloc.h"
void *calloc(size_t nmemb, size_t size)
{
size_t real_size = nmemb * size;
void *malloc_ret;
if (real_size % ALLIGN_BYTES)
real_size = ((real_size / ALLIGN_BYTES) + 1) * ALLIGN_BYTES;
malloc_ret = malloc(real_size);
if (!malloc_ret)
return (NULL);
// pthread_mutex_lock(&g_mut);
ft_memset(malloc_ret, 0, real_size); // no need to lock because pointer is internal until we return it, user can't call any of our function on it
// pthread_mutex_unlock(&g_mut);
return (malloc_ret);
}

BIN
srcs/ft_calloc.o Normal file

Binary file not shown.

99
srcs/ft_free.c Normal file
View file

@ -0,0 +1,99 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_free.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: thrieg < thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/11/19 15:44:05 by thrieg #+# #+# */
/* Updated: 2025/11/25 16:21:10 by thrieg ### ########.fr */
/* */
/* ************************************************************************** */
#include "../includes/ft_malloc.h"
// returns non-0 (1) when the function munmap the zone
int defrag_zone(t_zone *zone)
{
t_header *header = (t_header *)(zone + 1);
char *last_adr = ((char *)zone) + zone->size - sizeof(t_header);
while ((((char *)header) + header->size) < last_adr)
{
t_header *next_header = (t_header *)(((char *)header) + sizeof(t_header) + header->size);
if (!header->occupied && !next_header->occupied)
{
header->size = header->size + sizeof(t_header) + next_header->size;
}
else
{
header = next_header;
}
}
// if only 1 free header left, mmunmap the zone
if (header == (t_header *)(zone + 1) && !header->occupied)
{
if (zone->type == E_SMALL)
{
if (g_state.small_zone == zone)
{
if (zone->next)
g_state.small_zone = zone->next;
else
return (0); // last small zone, don't deallocate to avoid mmap stress
}
}
else if (zone->type == E_TINY)
{
if (g_state.tiny_zone == zone)
{
if (zone->next)
g_state.tiny_zone = zone->next;
else
return (0); // last tiny zone, don't deallocate to avoid mmap stress
}
}
if (zone->prev)
zone->prev->next = zone->next;
if (zone->next)
zone->next->prev = zone->prev;
munmap(zone, zone->size);
return (1);
}
return (0);
}
void free(void *ptr)
{
pthread_mutex_lock(&g_mut);
if (!ptr)
return ((void)pthread_mutex_unlock(&g_mut));
t_header *header = ((t_header *)ptr) - 1;
if (header->zone->type == E_LARGE)
{
if (header->zone->prev)
header->zone->prev->next = header->zone->next;
if (header->zone->next)
header->zone->next->prev = header->zone->prev;
if (header->zone == g_state.large_zone)
{
if (g_state.large_zone->next)
g_state.large_zone = g_state.large_zone->next;
else
g_state.large_zone = NULL;
}
void *ptr = header->zone;
size_t len = header->zone->size;
munmap(ptr, len);
}
else if (header->zone->type == E_SMALL)
{
header->occupied = false;
defrag_zone(header->zone);
}
else if (header->zone->type == E_TINY)
{
header->occupied = false;
defrag_zone(header->zone);
}
pthread_mutex_unlock(&g_mut);
}

BIN
srcs/ft_free.o Normal file

Binary file not shown.

35
srcs/ft_malloc.c Normal file
View file

@ -0,0 +1,35 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_malloc.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: thrieg < thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/11/17 15:02:55 by thrieg #+# #+# */
/* Updated: 2025/11/25 14:30:44 by thrieg ### ########.fr */
/* */
/* ************************************************************************** */
#include "../includes/ft_malloc.h"
void *malloc(size_t size)
{
pthread_mutex_lock(&g_mut);
if (!size || size % ALLIGN_BYTES)
size = ((size / ALLIGN_BYTES) + 1) * ALLIGN_BYTES;
void *ret = NULL;
if (size > SMALL_SIZE_MAX)
{
ret = add_large(size);
}
else if (size > TINY_SIZE_MAX)
{
ret = add_small(size);
}
else
{
ret = add_tiny(size);
}
pthread_mutex_unlock(&g_mut);
return (ret);
}

BIN
srcs/ft_malloc.o Normal file

Binary file not shown.

146
srcs/ft_realloc.c Normal file
View file

@ -0,0 +1,146 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_realloc.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: thrieg < thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/11/25 11:47:23 by thrieg #+# #+# */
/* Updated: 2025/11/28 16:37:22 by thrieg ### ########.fr */
/* */
/* ************************************************************************** */
#include "../includes/ft_malloc.h"
// returns non-0 (1) is the zone changes type to a higher type (tiny to small or small to large)
static bool is_upgraded(size_t size, t_type current_type)
{
if (size > SMALL_SIZE_MAX && current_type != E_LARGE)
return (1);
else if (size > TINY_SIZE_MAX && current_type != E_SMALL)
return (1);
else
return (0);
}
void *realloc(void *ptr, size_t size)
{
if (size == 0)
{
free(ptr);
return (NULL);
}
else if (!ptr)
{
return (malloc(size));
}
size_t original_size = size;
if (size % ALLIGN_BYTES)
size = ((size / ALLIGN_BYTES) + 1) * ALLIGN_BYTES;
void *ret = NULL;
pthread_mutex_lock(&g_mut);
t_header *header = ((t_header *)ptr) - 1;
if (header->zone->type == E_LARGE)
{
pthread_mutex_unlock(&g_mut);
ret = malloc(size);
if (!ret)
return (NULL);
pthread_mutex_lock(&g_mut);
if (original_size > header->size)
ft_memcpy(ret, ptr, header->size); // if grow, copy the entire last buffer
else
ft_memcpy(ret, ptr, original_size); // if shrink, copy the new amount of bytes from older buffer
pthread_mutex_unlock(&g_mut);
free(ptr);
pthread_mutex_lock(&g_mut);
}
else if (is_upgraded(size, header->zone->type))
{
pthread_mutex_unlock(&g_mut);
ret = malloc(size);
if (!ret)
return (NULL);
pthread_mutex_lock(&g_mut);
if (original_size > header->size)
ft_memcpy(ret, ptr, header->size); // if grow, copy the entire last buffer
else
ft_memcpy(ret, ptr, original_size); // if shrink, copy the new amount of bytes from older buffer
pthread_mutex_unlock(&g_mut);
free(ptr);
pthread_mutex_lock(&g_mut);
}
else if (header->zone->type == E_SMALL || header->zone->type == E_TINY)
{
t_header *next_header = (t_header *)(((char *)header) + sizeof(t_header) + header->size);
if ((char *)next_header > (((char *)header->zone) + header->zone->size - sizeof(t_header)))
next_header = NULL; // next header out of the zone
if (size > header->size)
{
if (next_header && !next_header->occupied && (header->size + next_header->size + sizeof(t_header)) >= size)
{
const size_t available_space = (header->size + next_header->size + sizeof(t_header));
if (available_space - size > sizeof(t_header))
{
// Split the block: create a new header in the remaining space
char *new_addr = (char *)(header + 1) + size;
t_header *newhdr = (t_header *)new_addr;
newhdr->size = available_space - size - sizeof(t_header);
newhdr->occupied = false;
newhdr->zone = header->zone;
header->size = size;
}
else
{
header->size = available_space;
}
ret = ptr;
}
else
{
pthread_mutex_unlock(&g_mut);
ret = malloc(size);
if (!ret)
return (NULL);
pthread_mutex_lock(&g_mut);
if (original_size > header->size)
ft_memcpy(ret, ptr, header->size); // if grow, copy the entire last buffer
else
ft_memcpy(ret, ptr, original_size); // if shrink, copy the new amount of bytes from older buffer
pthread_mutex_unlock(&g_mut);
free(ptr);
pthread_mutex_lock(&g_mut);
}
}
else
{
ret = ptr; // in all case we just return the original ptr, rest is just internal logic
size_t available_space = header->size - size; // zones are defragmented so all available contiguous space must be in a single header
if (next_header && !next_header->occupied)
available_space += next_header->size + sizeof(t_header);
if (available_space > sizeof(t_header))
{
if (available_space > sizeof(t_header))
{
// Split the block: create a new header in the remaining space
char *new_addr = (char *)(header + 1) + size;
t_header *newhdr = (t_header *)new_addr;
newhdr->size = available_space - sizeof(t_header);
newhdr->occupied = false;
newhdr->zone = header->zone;
header->size = size;
}
else
{
header->size = available_space;
}
}
}
}
pthread_mutex_unlock(&g_mut);
return (ret);
}

BIN
srcs/ft_realloc.o Normal file

Binary file not shown.

267
srcs/init_state.c Normal file
View file

@ -0,0 +1,267 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* init_state.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: thrieg < thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/11/18 16:44:13 by thrieg #+# #+# */
/* Updated: 2025/11/28 16:41:55 by thrieg ### ########.fr */
/* */
/* ************************************************************************** */
#include "../includes/ft_malloc.h"
pthread_mutex_t g_mut = PTHREAD_MUTEX_INITIALIZER;
t_state g_state = {.tiny_zone = NULL, .small_zone = NULL, .large_zone = NULL};
// only call this for TINY or SMALL
void *add_page(t_type type)
{
size_t size;
if (type == E_TINY)
size = ((((((TINY_SIZE_MAX + sizeof(t_header)) * 100) + sizeof(t_zone))) / getpagesize()) + 1) * getpagesize();
else if (type == E_SMALL)
size = ((((((SMALL_SIZE_MAX + sizeof(t_header)) * 100) + sizeof(t_zone))) / getpagesize()) + 1) * getpagesize();
else
return (NULL); // TODO handle error somehow
t_zone *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED)
return (NULL);
ptr->size = size;
if (type == E_TINY)
{
ptr->type = E_TINY;
ptr->prev = NULL;
t_header *header = (t_header *)(ptr + 1);
header->occupied = false;
header->size = size - sizeof(t_zone) - sizeof(t_header);
header->zone = ptr;
ptr->next = g_state.tiny_zone; // tiny_zone can be NULL but that's fine
if (g_state.tiny_zone)
g_state.tiny_zone->prev = ptr;
g_state.tiny_zone = ptr;
}
else if (type == E_SMALL)
{
ptr->type = E_SMALL;
ptr->prev = NULL;
t_header *header = (t_header *)(ptr + 1);
header->occupied = false;
header->size = size - sizeof(t_zone) - sizeof(t_header);
header->zone = ptr;
ptr->next = g_state.small_zone; // small_zone can be NULL but that's fine
if (g_state.small_zone)
g_state.small_zone->prev = ptr;
g_state.small_zone = ptr;
}
return (ptr);
}
// returns the start of the buffer (returned by malloc)
void *add_large(size_t size)
{
size = (((size + sizeof(t_header) + sizeof(t_zone)) / getpagesize()) + 1) * getpagesize();
t_zone *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED)
return (NULL);
ptr->size = size;
ptr->type = E_LARGE;
ptr->prev = NULL;
ptr->next = g_state.large_zone; // large_zone can be NULL but that's fine
if (g_state.large_zone)
g_state.large_zone->prev = ptr;
g_state.large_zone = ptr;
t_header *header = (t_header *)(ptr + 1);
header->occupied = true;
header->size = size - sizeof(t_zone) - sizeof(t_header);
header->zone = ptr;
return ((void *)(header + 1));
}
// returns the start of the buffer (returned by malloc)
// size has to be alligned
void *add_small(size_t size)
{
t_zone *zone;
t_header *hdr;
void *result = NULL;
zone = g_state.small_zone;
while (zone && !result)
{
char *zone_start = (char *)zone;
char *zone_end = zone_start + zone->size;
// First header is right after the zone struct
hdr = (t_header *)(zone + 1);
while ((char *)hdr + sizeof(t_header) <= zone_end)
{
if (!hdr->occupied && hdr->size >= size)
{
// Found a free block big enough
size_t remaining = hdr->size - size;
if (remaining > sizeof(t_header))
{
// Split the block: create a new header in the remaining space
char *new_addr = (char *)(hdr + 1) + size;
t_header *newhdr = (t_header *)new_addr;
newhdr->size = remaining - sizeof(t_header);
newhdr->occupied = false;
newhdr->zone = zone;
hdr->size = size;
}
// else: not enough room for another header, we just don't touch the size
hdr->occupied = true;
result = (void *)(hdr + 1);
break;
}
char *next_addr = (char *)(hdr + 1) + hdr->size;
// If there's no room for another valid header, stop.
if (next_addr + sizeof(t_header) > zone_end)
break;
hdr = (t_header *)next_addr;
}
zone = zone->next;
}
if (result)
return result;
// not enough room, create a new page
zone = (t_zone *)add_page(E_SMALL);
if (!zone)
return (NULL);
hdr = (t_header *)(zone + 1);
if (hdr->size >= size)
{
size_t remaining = hdr->size - size;
if (remaining > sizeof(t_header)) // should always be true (enough room for 100 allocs in a page)
{
char *new_addr = (char *)(hdr + 1) + size;
t_header *newhdr = (t_header *)new_addr;
newhdr->size = remaining - sizeof(t_header);
newhdr->occupied = false;
newhdr->zone = zone;
hdr->size = size;
}
hdr->occupied = true;
result = (void *)(hdr + 1);
}
else
{
// wtf, not possible, but nice to handle I guess
result = NULL;
}
return (result);
}
// returns the start of the buffer (returned by malloc)
// size has to be alligned
void *add_tiny(size_t size)
{
t_zone *zone;
t_header *hdr;
void *result = NULL;
zone = g_state.tiny_zone;
while (zone && !result)
{
char *zone_start = (char *)zone;
char *zone_end = zone_start + zone->size;
// First header is right after the zone struct
hdr = (t_header *)(zone + 1);
while ((char *)hdr + sizeof(t_header) <= zone_end)
{
if (!hdr->occupied && hdr->size >= size)
{
// Found a free block big enough
size_t remaining = hdr->size - size;
if (remaining > sizeof(t_header))
{
// Split the block: create a new header in the remaining space
char *new_addr = (char *)(hdr + 1) + size;
t_header *newhdr = (t_header *)new_addr;
newhdr->size = remaining - sizeof(t_header);
newhdr->occupied = false;
newhdr->zone = zone;
hdr->size = size;
}
// else: not enough room for another header, we just
hdr->occupied = true;
result = (void *)(hdr + 1);
break;
}
char *next_addr = (char *)(hdr + 1) + hdr->size;
// If there's no room for another valid header, stop.
if (next_addr + sizeof(t_header) > zone_end)
break;
hdr = (t_header *)next_addr;
}
zone = zone->next;
}
if (result)
return result;
// not enough room, create a new page
zone = (t_zone *)add_page(E_TINY);
if (!zone)
return (NULL);
hdr = (t_header *)(zone + 1);
// hdr->size should always be >= size here
if (hdr->size >= size)
{
size_t remaining = hdr->size - size;
if (remaining > sizeof(t_header)) // should always be true (enough room for 100 allocs in a page)
{
char *new_addr = (char *)(hdr + 1) + size;
t_header *newhdr = (t_header *)new_addr;
newhdr->size = remaining - sizeof(t_header);
newhdr->occupied = false;
newhdr->zone = zone;
hdr->size = size;
}
hdr->occupied = true;
result = (void *)(hdr + 1);
}
else
{
// wtf, not possible, but nice to handle I guess
result = NULL;
}
return (result);
}

BIN
srcs/init_state.o Normal file

Binary file not shown.