155 lines
5.4 KiB
C
155 lines
5.4 KiB
C
/* ************************************************************************** */
|
|
/* */
|
|
/* ::: :::::::: */
|
|
/* ft_realloc.c :+: :+: :+: */
|
|
/* +:+ +:+ +:+ */
|
|
/* By: thrieg < thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
|
|
/* +#+#+#+#+#+ +#+ */
|
|
/* Created: 2025/11/25 11:47:23 by thrieg #+# #+# */
|
|
/* Updated: 2025/12/08 16:02:18 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);
|
|
if (!g_state.is_init)
|
|
{
|
|
init_env_variables(); // realloc shouldn't ever be called first with a non-NULL ptr
|
|
return (NULL); // should I just let it segfault here like the real realloc?
|
|
}
|
|
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));
|
|
const size_t original_space = header->size;
|
|
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;
|
|
}
|
|
pthread_mutex_unlock(&g_mut); // doesn't need to stay locked because the user is not supposed to free or realloc this ptr or change its content before this realloc returns
|
|
if (g_state.patern)
|
|
ft_memset((char *)ptr + original_space, g_state.patern, header->size - original_space); // should I use original_size to only perturb the actually requested bytes instead of the bytes I allocate?
|
|
return (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);
|
|
}
|