LibC: Make malloc thread safe with pthread_spinlock

This commit is contained in:
Bananymous 2025-04-15 22:31:54 +03:00
parent cf59f89bfb
commit cc2b4967ea
1 changed files with 25 additions and 6 deletions

View File

@ -2,6 +2,7 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <pthread.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <sys/mman.h>
@ -72,6 +73,8 @@ struct malloc_info_t
static malloc_info_t s_malloc_info; static malloc_info_t s_malloc_info;
static auto& s_malloc_pools = s_malloc_info.pools; static auto& s_malloc_pools = s_malloc_info.pools;
static pthread_spinlock_t s_malloc_lock;
static bool allocate_pool(size_t pool_index) static bool allocate_pool(size_t pool_index)
{ {
auto& pool = s_malloc_pools[pool_index]; auto& pool = s_malloc_pools[pool_index];
@ -200,19 +203,31 @@ void* malloc(size_t size)
// try to find any already existing pools that we can allocate in // try to find any already existing pools that we can allocate in
for (size_t i = first_usable_pool; i < s_malloc_pool_count; i++) for (size_t i = first_usable_pool; i < s_malloc_pool_count; i++)
if (s_malloc_pools[i].start != nullptr) {
if (void* ret = allocate_from_pool(i, size)) if (s_malloc_pools[i].start == nullptr)
return ret; continue;
pthread_spin_lock(&s_malloc_lock);
void* ret = allocate_from_pool(i, size);
pthread_spin_unlock(&s_malloc_lock);
if (ret != nullptr)
return ret;
}
// allocate new pool // allocate new pool
for (size_t i = first_usable_pool; i < s_malloc_pool_count; i++) for (size_t i = first_usable_pool; i < s_malloc_pool_count; i++)
{ {
if (s_malloc_pools[i].start != nullptr) if (s_malloc_pools[i].start != nullptr)
continue; continue;
if (!allocate_pool(i))
pthread_spin_lock(&s_malloc_lock);
void* ret = nullptr;
if (allocate_pool(i))
ret = allocate_from_pool(i, size);
pthread_spin_unlock(&s_malloc_lock);
if (ret == nullptr)
break; break;
// NOTE: always works since we just created the pool return ret;
return allocate_from_pool(i, size);
} }
errno = ENOMEM; errno = ENOMEM;
@ -258,6 +273,8 @@ void free(void* ptr)
if (ptr == nullptr) if (ptr == nullptr)
return; return;
pthread_spin_lock(&s_malloc_lock);
auto* node = node_from_data_pointer(ptr); auto* node = node_from_data_pointer(ptr);
node->allocated = false; node->allocated = false;
@ -279,6 +296,8 @@ void free(void* ptr)
node->prev_free = nullptr; node->prev_free = nullptr;
node->next_free = pool.free_list; node->next_free = pool.free_list;
pool.free_list = node; pool.free_list = node;
pthread_spin_unlock(&s_malloc_lock);
} }
void* calloc(size_t nmemb, size_t size) void* calloc(size_t nmemb, size_t size)