From b0ec0f1a1a2e9e1039a0c5a8a5192148d98120b1 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 7 May 2023 23:57:01 +0300 Subject: [PATCH] Kernel: We add FixedWidthAllocators on demand On SYS_ALLOC we will add a new FixedWidthAllocator if the old ones are already full or we don't have one with proper size. This allows arbitary number of allocations as long as you have enough memory available :) Next I will be writing a general allocator for allocations larger than 4096 bytes which should make SYS_ALLOC syscall complete :) --- .../kernel/Memory/FixedWidthAllocator.h | 5 +- kernel/include/kernel/Process.h | 2 +- kernel/kernel/Memory/FixedWidthAllocator.cpp | 21 +++++--- kernel/kernel/Process.cpp | 53 +++++++++++++++---- userspace/test.c | 23 +++++--- 5 files changed, 77 insertions(+), 27 deletions(-) diff --git a/kernel/include/kernel/Memory/FixedWidthAllocator.h b/kernel/include/kernel/Memory/FixedWidthAllocator.h index 44a0bd58..b3683603 100644 --- a/kernel/include/kernel/Memory/FixedWidthAllocator.h +++ b/kernel/include/kernel/Memory/FixedWidthAllocator.h @@ -21,6 +21,9 @@ namespace Kernel uint32_t allocation_size() const { return m_allocation_size; } + uint32_t allocations() const { return m_allocations; } + uint32_t max_allocations() const; + private: struct node { @@ -44,7 +47,7 @@ namespace Kernel node* m_free_list { nullptr }; node* m_used_list { nullptr }; - uint32_t m_allocated { 0 }; + uint32_t m_allocations { 0 }; }; } \ No newline at end of file diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 35d26d44..803fa50e 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -94,7 +94,7 @@ namespace Kernel BAN::String m_working_directory; BAN::Vector m_threads; - BAN::Vector m_fixed_width_allocators; + BAN::LinkedList m_fixed_width_allocators; MMU* m_mmu { nullptr }; TTY* m_tty { nullptr }; diff --git a/kernel/kernel/Memory/FixedWidthAllocator.cpp b/kernel/kernel/Memory/FixedWidthAllocator.cpp index e0865cec..e08d36c3 100644 --- a/kernel/kernel/Memory/FixedWidthAllocator.cpp +++ b/kernel/kernel/Memory/FixedWidthAllocator.cpp @@ -49,7 +49,7 @@ namespace Kernel , m_allocated_pages(other.m_allocated_pages) , m_free_list(other.m_free_list) , m_used_list(other.m_used_list) - , m_allocated(other.m_allocated) + , m_allocations(other.m_allocations) { other.m_process = nullptr; } @@ -81,9 +81,8 @@ namespace Kernel paddr_t FixedWidthAllocator::allocate() { - // FIXME: We should get allocate more memory if we run out of - // nodes in free list. - ASSERT(m_free_list); + if (m_free_list == nullptr) + return 0; node* node = m_free_list; @@ -101,7 +100,7 @@ namespace Kernel m_used_list->prev = node; m_used_list = node; - m_allocated++; + m_allocations++; allocate_page_for_node_if_needed(node); return address_of_node(node); } @@ -110,12 +109,13 @@ namespace Kernel { if (address % m_allocation_size) return false; + if (m_allocations == 0) + return false; node* node = node_from_address(address); if (node == nullptr) return false; - if (!node->allocated) { dwarnln("deallocate called on unallocated address"); @@ -123,6 +123,8 @@ namespace Kernel } node->allocated = false; + if (node == m_used_list) + m_used_list = node->next; if (node->prev) node->prev->next = node->next; if (node->next) @@ -135,10 +137,15 @@ namespace Kernel m_free_list->prev = node; m_free_list = node; - m_allocated--; + m_allocations--; return true; } + uint32_t FixedWidthAllocator::max_allocations() const + { + return PAGE_SIZE / sizeof(node); + } + vaddr_t FixedWidthAllocator::address_of_node(const node* node) const { uint32_t index = node - (struct node*)m_nodes_page; diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 28fe10ab..b2c26123 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -105,11 +105,6 @@ namespace Kernel delete elf; - MUST(process->m_fixed_width_allocators.emplace_back(process, 64)); - MUST(process->m_fixed_width_allocators.emplace_back(process, 256)); - MUST(process->m_fixed_width_allocators.emplace_back(process, 1024)); - MUST(process->m_fixed_width_allocators.emplace_back(process, 4096)); - register_process(process); return process; } @@ -378,19 +373,55 @@ namespace Kernel return {}; } + static constexpr uint16_t next_power_of_two(uint16_t value) + { + value--; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + return value + 1; + } + BAN::ErrorOr Process::allocate(size_t bytes) { - for (auto& allocator : m_fixed_width_allocators) - if (bytes <= allocator.allocation_size()) - return (void*)allocator.allocate(); - return BAN::Error::from_errno(ENOMEM); + if (bytes <= PAGE_SIZE) + { + // Do fixed width allocation + size_t allocation_size = next_power_of_two(bytes); + ASSERT(bytes <= allocation_size); + + LockGuard _(m_lock); + + for (auto& allocator : m_fixed_width_allocators) + if (allocator.allocation_size() == allocation_size && allocator.allocations() < allocator.max_allocations()) + return (void*)allocator.allocate(); + + MUST(m_fixed_width_allocators.emplace_back(this, allocation_size)); + return (void*)m_fixed_width_allocators.back().allocate(); + } + else + { + // TODO: Do general allocation + return BAN::Error::from_errno(ENOMEM); + } } void Process::free(void* ptr) { - for (auto& allocator : m_fixed_width_allocators) - if (allocator.deallocate((vaddr_t)ptr)) + LockGuard _(m_lock); + + for (auto it = m_fixed_width_allocators.begin(); it != m_fixed_width_allocators.end(); it++) + { + if (it->deallocate((vaddr_t)ptr)) + { + // TODO: This might be too much. Maybe we should only + // remove allocators when we have low memory... ? + if (it->allocations() == 0) + m_fixed_width_allocators.remove(it); return; + } + } dwarnln("free called on pointer that was not allocated"); } diff --git a/userspace/test.c b/userspace/test.c index c4646947..92b551cd 100644 --- a/userspace/test.c +++ b/userspace/test.c @@ -1,25 +1,34 @@ #include #include +#define N 512 + int main() { - for (int i = 0; i < 10; i++) + for (int i = 0; i <= 10; i++) { - int* ptrs[10]; - for (int j = 0; j < 10; j++) + int** ptrs = malloc(N * sizeof(int*)); + if (ptrs == NULL) { - ptrs[j] = malloc(10); + perror("malloc"); + return 1; + } + for (int j = 0; j < N; j++) + { + ptrs[j] = malloc(sizeof(int)); if (ptrs[j] == NULL) { perror("malloc"); return 1; } *ptrs[j] = j; - putc('0' + *ptrs[j], stdout); + putchar('0' + *ptrs[j] % 10); } - for (int j = 0; j < 10; j++) + putchar('\n'); + + for (int j = 0; j < N; j++) free(ptrs[j]); - putc('\n', stdout); + free(ptrs); } return 0;