Reputation: 45
I am implementing my own memory allocator but I would like to address thread safety. Here is my implementation of malloc:
pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER; /*< Mutex for protecting the linked list */
void *malloc(size_t size)
{
pthread_mutex_lock(&alloc_mutex);
size_t total_size = size + sizeof(struct mem_block);
size_t aligned_size = total_size;
if (total_size % 8 !=0) {
aligned_size = (total_size / 8) * 8 + 8;
}
LOG("Allocation: request size = %zu, total size = %zu, aligned size = %zu\n", size, total_size, aligned_size);
struct mem_block *reused_block = reuse(aligned_size);
if(reused_block != NULL){
return reused_block + 1;
}
int page_size = getpagesize();
size_t num_pages = aligned_size / page_size;
if(aligned_size % page_size != 0){
num_pages++;
}
size_t region_size = num_pages * page_size;
struct mem_block *block = mmap(NULL, region_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(block == MAP_FAILED){
perror("mmap");
return NULL;
}
snprintf(block->name, 32, "Allocation %lu", g_allocations++);
block->size = region_size;
block->free = true;
block->region_id = g_regions++;
if(g_head == NULL && g_tail == NULL){
block->next = NULL;
block->prev = NULL;
g_head = block;
g_tail = block;
}
else {
g_tail->next = block;
block->prev = g_tail;
block->next = NULL;
g_tail = block;
}
split_block(block, aligned_size);
block->free = false;
pthread_mutex_unlock(&alloc_mutex);
return block+1;
}
My main question is: Where would I need to lock and unlock for my implementation to be thread safe? Because rn it is not.
Upvotes: 0
Views: 438
Reputation: 5933
You could implement two functions, one called 'malloc_impl' with the main functionality and another one called 'malloc' which locks the mutex, calls 'malloc_impl' and unlocks it.
Another solution would be to use 'goto'. Depending on the case, jump to the specific label, in that way, you have to specify the unlock only once.
Example:
void *block = NULL;
if (err_cond)
goto fail;
if (cond)
goto done;
// do some other stuff
goto done;
fail:
block = NULL;
done:
unlock_mutex();
return block;
p.s. yes, gotos are evil, but sometimes very (very) useful.
Upvotes: 2