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;