/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* init_state.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: thrieg +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/11/18 16:44:13 by thrieg #+# #+# */ /* Updated: 2025/12/13 05:50:48 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, .patern = 0, .is_init = false}; void init_env_variables() { char *env = getenv("MALLOC_PERTURB_"); // this doesn't call malloc, returns a pointer from **environ if (env) { int overflow = 0; int v = ft_atoi(env, &overflow); if (!overflow && v > 0 && v <= 255) g_state.patern = (unsigned char)v; } g_state.is_init = true; } //inserts a page in the linked list whilst keeping the zones sorted in ascending address static void zone_insert_sorted(t_zone **head, t_zone *z) { t_zone *cur; z->prev = NULL; z->next = NULL; if (*head == NULL) { *head = z; return; } cur = *head; // insert before head if ((uintptr_t)z < (uintptr_t)cur) { z->next = cur; cur->prev = z; *head = z; return; } // walk until the next node is after z (or end) while (cur->next && (uintptr_t)cur->next < (uintptr_t)z) cur = cur->next; // insert after cur z->next = cur->next; z->prev = cur; if (cur->next) cur->next->prev = z; cur->next = z; } // 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; zone_insert_sorted(&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; zone_insert_sorted(&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; t_header *header = (t_header *)(ptr + 1); header->occupied = true; header->size = size - sizeof(t_zone) - sizeof(t_header); header->zone = ptr; zone_insert_sorted(&g_state.large_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); }