diff --git a/include/cia-mem.h b/include/cia-mem.h index 8ee5efa..75309e2 100644 --- a/include/cia-mem.h +++ b/include/cia-mem.h @@ -3,6 +3,8 @@ void *cia_ptr_alignf(void *ptr, u64 alignment); void *cia_ptr_alignb(void *ptr, u64 alignment); +u64 cia_size_alignf(u64 size, u64 alignment); +u64 cia_size_alignb(u64 size, u64 alignment); #define CIA_MEM_OP_ALLOC 1 #define CIA_MEM_OP_FREE 2 @@ -37,3 +39,31 @@ void *cia_arena_alloc(Cia_Arena *arena, u64 size); void *cia_arena_alloc_aligned(Cia_Arena *arena, u64 size, u64 align); void cia_arena_free_all(Cia_Arena *arena); void cia_arena_destroy(Cia_Arena *arena); + +struct Cia_Pool_Bucket typedef Cia_Pool_Bucket; +struct Cia_Pool_Bucket { + Cia_Pool_Bucket *next; +}; + +struct Cia_Pool_Buffer_Header typedef Cia_Pool_Buffer_Header; +struct Cia_Pool_Buffer_Header { + Cia_Pool_Buffer_Header *next; + u64 free_buckets_count; + Cia_Pool_Bucket *free_head; +}; + +struct Cia_Pool typedef Cia_Pool; +struct Cia_Pool { + Cia_Allocator allocator; + Cia_Pool_Buffer_Header *first; + u64 buffer_size; + u64 bucket_size; + u64 alignment; +}; + +void cia_pool_create(Cia_Pool *pool, Cia_Allocator backing_allocator, u64 buffer_size, u64 element_size, u64 alignment); +void *cia_pool_alloc(Cia_Pool *pool); +void cia_pool_free(Cia_Pool *pool, void *ptr); +void cia_pool_free_all(Cia_Pool *pool); +void cia_pool_destroy(Cia_Pool *pool); + diff --git a/src/impl/cia-mem/pool.c b/src/impl/cia-mem/pool.c new file mode 100644 index 0000000..01912f8 --- /dev/null +++ b/src/impl/cia-mem/pool.c @@ -0,0 +1,94 @@ + +static void pool_reinit_buffer(Cia_Pool *pool, u8 *buffer) { + Cia_Pool_Buffer_Header *header = (Cia_Pool_Buffer_Header *)buffer; + u64 header_size = sizeof(Cia_Pool_Buffer_Header); + u64 header_size_aligned = cia_size_alignf(header_size, pool->alignment); + u8 *buckets = buffer + header_size_aligned; + u64 remaining_size = pool->buffer_size - header_size_aligned; + u64 buckets_count = remaining_size / pool->bucket_size; + header->free_buckets_count = buckets_count; + u64 buckets_size = buckets_count * pool->bucket_size; + // Initialize every bucket as free + u64 bucket_offset = header_size_aligned + buckets_size; + Cia_Pool_Bucket *next_bucket = NULL; + do { + bucket_offset -= pool->bucket_size; + Cia_Pool_Bucket *bucket = (Cia_Pool_Bucket *)(buffer + bucket_offset); + bucket->next = next_bucket; + next_bucket = bucket; + } while(bucket_offset > header_size_aligned); + header->free_head = next_bucket; +} + +void cia_pool_create(Cia_Pool *pool, Cia_Allocator backing_allocator, u64 buffer_size, u64 bucket_size, u64 alignment) { + pool->allocator = backing_allocator; + pool->buffer_size = buffer_size; + pool->bucket_size = bucket_size; + pool->alignment = alignment; + // If the unallocated element can't hold a bucket, increase the size of the element + if(pool->bucket_size < sizeof(Cia_Pool_Bucket)) { + pool->bucket_size = sizeof(Cia_Pool_Bucket); + } + // Make element size a multiple of the alignment + pool->bucket_size = cia_size_alignf(pool->bucket_size, pool->alignment); + // Allocate and initialize the first buffer + pool->first = allocator_alloc(&pool->allocator, pool->buffer_size, pool->alignment); + pool_reinit_buffer(pool, (u8 *)pool->first); +} + +void *cia_pool_alloc(Cia_Pool *pool) { + Cia_Pool_Buffer_Header *buffer = pool->first; + // Find buffer with free data in it + while(buffer != NULL) { + if(buffer->free_buckets_count > 0) { + break; + } + buffer = buffer->next; + } + // If none have it, then create a new buffer + if(buffer == NULL) { + void *buffer_mem = allocator_alloc(&pool->allocator, pool->buffer_size, pool->alignment); + pool_reinit_buffer(pool, buffer_mem); + Cia_Pool_Buffer_Header *header = buffer_mem; + header->next = pool->first; + pool->first = header; + buffer = header; + } + // Remove item from free list and return it + void *addr = buffer->free_head; + buffer->free_head = buffer->free_head->next; + return addr; +} + +void cia_pool_free(Cia_Pool *pool, void *ptr) { + // Check which buffer the allocation is from + Cia_Pool_Buffer_Header *source = NULL; + for(Cia_Pool_Buffer_Header *buffer = pool->first; buffer != NULL; buffer = buffer->next) { + void *buffer_start = buffer; + void *buffer_end = (u8 *)buffer + pool->buffer_size; + if(buffer_start < ptr && ptr < buffer_end) { + source = buffer; + break; + } + } + // Add bucket to free list + Cia_Pool_Bucket *bucket = ptr; + bucket->next = source->free_head; + source->free_head = bucket; +} + +void cia_pool_free_all(Cia_Pool *pool) { + // Deallocate all buffers except the first one + for(Cia_Pool_Buffer_Header *buffer = pool->first->next; buffer != NULL; buffer = buffer->next) { + allocator_free_size(&pool->allocator, buffer, pool->buffer_size); + } + // Reinit the first buffer + pool_reinit_buffer(pool, (u8 *)pool->first); +} + +void cia_pool_destroy(Cia_Pool *pool) { + // Simply deallocate all the buffers + for(Cia_Pool_Buffer_Header *buffer = pool->first; buffer != NULL; buffer = buffer->next) { + allocator_free_size(&pool->allocator, buffer, pool->buffer_size); + } +} \ No newline at end of file diff --git a/src/impl/cia-mem/util.c b/src/impl/cia-mem/util.c index d33ed99..9b179e2 100644 --- a/src/impl/cia-mem/util.c +++ b/src/impl/cia-mem/util.c @@ -9,4 +9,12 @@ void *cia_ptr_alignb(void *ptr, u64 alignment) { u64 addr = (u64)ptr; u64 aligned = addr & ~(alignment - 1); return (void *)aligned; +} + +u64 cia_size_alignf(u64 size, u64 alignment) { + return (size + alignment - 1) & ~(alignment - 1); +} + +u64 cia_size_alignb(u64 size, u64 alignment) { + return size & ~(alignment - 1); } \ No newline at end of file diff --git a/src/impl/stdlib-file/file.c b/src/impl/stdlib-file/file.c index 3d482ed..0ef014f 100644 --- a/src/impl/stdlib-file/file.c +++ b/src/impl/stdlib-file/file.c @@ -3,17 +3,17 @@ FILE *stdin; FILE *stdout; FILE *stderr; -// TODO: memory allocation -static FILE _files[64]; -static int _files_cnt = 0; +static Cia_Pool _page_allocator; +static Cia_Pool _file_pool; static void _fileapi_init() { + cia_pool_create(&_file_pool, cia_allocator_pages(), 0x1000, sizeof(FILE), 16); + FILE *stdin = cia_pool_alloc(&_file_pool); + FILE *stdout = cia_pool_alloc(&_file_pool); + FILE *stderr = cia_pool_alloc(&_file_pool); _rt_file_std_handles_init(); - stdin = &_files[_files_cnt++]; stdin->rt_file = _rt_file_stdin; - stdout = &_files[_files_cnt++]; stdout->rt_file = _rt_file_stdout; - stderr = &_files[_files_cnt++]; stderr->rt_file = _rt_file_stderr; } @@ -30,8 +30,7 @@ FILE *fopen(char const *restrict filename, char const *restrict mode) { if(status != _RT_STATUS_OK) { return NULL; } - FILE *file = &_files[_files_cnt]; - _files_cnt += 1; + FILE *file = cia_pool_alloc(&_file_pool); file->rt_file = rt_file; return file; } diff --git a/src/library.json b/src/library.json index 2e895b8..3cd9803 100644 --- a/src/library.json +++ b/src/library.json @@ -61,6 +61,7 @@ apis: [ "util.c", "allocator.c", "arena.c", + "pool.c", ], reqs: [ "rt_api_memory" @@ -84,7 +85,8 @@ apis: [ "file.c" ], reqs: [ - "rt_api_file" + "rt_api_file", + "cia_memory", ] } ]