Kernel/LibC: add free function for FixedWidthAllocator
I have to rework the syscall API and allocators in process. For now this works well enough :)
This commit is contained in:
@@ -17,7 +17,7 @@ namespace Kernel
|
||||
~FixedWidthAllocator();
|
||||
|
||||
vaddr_t allocate();
|
||||
void deallocate(vaddr_t);
|
||||
bool deallocate(vaddr_t);
|
||||
|
||||
uint32_t allocation_size() const { return m_allocation_size; }
|
||||
|
||||
@@ -26,8 +26,10 @@ namespace Kernel
|
||||
{
|
||||
node* prev { nullptr };
|
||||
node* next { nullptr };
|
||||
bool allocated { false };
|
||||
};
|
||||
vaddr_t address_of(const node*) const;
|
||||
vaddr_t address_of_node(const node*) const;
|
||||
node* node_from_address(vaddr_t) const;
|
||||
void allocate_page_for_node_if_needed(const node*);
|
||||
|
||||
private:
|
||||
|
||||
@@ -57,6 +57,7 @@ namespace Kernel
|
||||
BAN::ErrorOr<void> set_working_directory(BAN::StringView);
|
||||
|
||||
BAN::ErrorOr<void*> allocate(size_t);
|
||||
void free(void*);
|
||||
|
||||
void termid(char*) const;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define SYS_SEEK 6
|
||||
#define SYS_OPEN 7
|
||||
#define SYS_ALLOC 8
|
||||
#define SYS_FREE 9
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@@ -87,6 +87,9 @@ namespace Kernel
|
||||
|
||||
node* node = m_free_list;
|
||||
|
||||
ASSERT(!node->allocated);
|
||||
node->allocated = true;
|
||||
|
||||
m_free_list = node->next;
|
||||
if (m_free_list)
|
||||
m_free_list->prev = nullptr;
|
||||
@@ -100,23 +103,50 @@ namespace Kernel
|
||||
|
||||
m_allocated++;
|
||||
allocate_page_for_node_if_needed(node);
|
||||
return address_of(node);
|
||||
return address_of_node(node);
|
||||
}
|
||||
|
||||
void FixedWidthAllocator::deallocate(paddr_t addr)
|
||||
bool FixedWidthAllocator::deallocate(vaddr_t address)
|
||||
{
|
||||
(void)addr;
|
||||
ASSERT_NOT_REACHED();
|
||||
if (address % m_allocation_size)
|
||||
return false;
|
||||
|
||||
node* node = node_from_address(address);
|
||||
if (node == nullptr)
|
||||
return false;
|
||||
|
||||
|
||||
if (!node->allocated)
|
||||
{
|
||||
dwarnln("deallocate called on unallocated address");
|
||||
return true;
|
||||
}
|
||||
node->allocated = false;
|
||||
|
||||
if (node->prev)
|
||||
node->prev->next = node->next;
|
||||
if (node->next)
|
||||
node->next->prev = node->prev;
|
||||
|
||||
node->next = m_free_list;
|
||||
node->prev = nullptr;
|
||||
|
||||
if (m_free_list)
|
||||
m_free_list->prev = node;
|
||||
m_free_list = node;
|
||||
|
||||
m_allocated--;
|
||||
return true;
|
||||
}
|
||||
|
||||
vaddr_t FixedWidthAllocator::address_of(const node* node) const
|
||||
vaddr_t FixedWidthAllocator::address_of_node(const node* node) const
|
||||
{
|
||||
uint32_t index = node - (struct node*)m_nodes_page;
|
||||
|
||||
uint32_t page_index = index / (PAGE_SIZE / sizeof(struct node));
|
||||
uint32_t page_index = index / (PAGE_SIZE / m_allocation_size);
|
||||
ASSERT(page_index < PAGE_SIZE / sizeof(vaddr_t));
|
||||
|
||||
uint32_t offset = index % (PAGE_SIZE / sizeof(struct node));
|
||||
uint32_t offset = index % (PAGE_SIZE / m_allocation_size);
|
||||
|
||||
vaddr_t page_begin = ((vaddr_t*)m_allocated_pages)[page_index];
|
||||
ASSERT(page_begin);
|
||||
@@ -124,11 +154,38 @@ namespace Kernel
|
||||
return page_begin + offset * m_allocation_size;
|
||||
}
|
||||
|
||||
FixedWidthAllocator::node* FixedWidthAllocator::node_from_address(vaddr_t address) const
|
||||
{
|
||||
// TODO: This probably should be optimized from O(n) preferably to O(1) but I
|
||||
// don't want to think about performance now.
|
||||
|
||||
ASSERT(address % m_allocation_size == 0);
|
||||
|
||||
vaddr_t page_begin = address / PAGE_SIZE * PAGE_SIZE;
|
||||
|
||||
for (uint32_t page_index = 0; page_index < PAGE_SIZE / sizeof(vaddr_t); page_index++)
|
||||
{
|
||||
vaddr_t vaddr = ((vaddr_t*)m_allocated_pages)[page_index];
|
||||
if (vaddr != page_begin)
|
||||
continue;
|
||||
|
||||
uint32_t offset = (address - page_begin) / m_allocation_size;
|
||||
|
||||
node* result = (node*)m_nodes_page;
|
||||
result += page_index * PAGE_SIZE / m_allocation_size;
|
||||
result += offset;
|
||||
ASSERT(address_of_node(result) == address);
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FixedWidthAllocator::allocate_page_for_node_if_needed(const node* node)
|
||||
{
|
||||
uint32_t index = node - (struct node*)m_nodes_page;
|
||||
|
||||
uint32_t page_index = index / (PAGE_SIZE / sizeof(struct node));
|
||||
uint32_t page_index = index / (PAGE_SIZE / m_allocation_size);
|
||||
ASSERT(page_index < PAGE_SIZE / sizeof(vaddr_t));
|
||||
|
||||
vaddr_t& page_vaddr = ((vaddr_t*)m_allocated_pages)[page_index];
|
||||
|
||||
@@ -386,6 +386,14 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
}
|
||||
|
||||
void Process::free(void* ptr)
|
||||
{
|
||||
for (auto& allocator : m_fixed_width_allocators)
|
||||
if (allocator.deallocate((vaddr_t)ptr))
|
||||
return;
|
||||
dwarnln("free called on pointer that was not allocated");
|
||||
}
|
||||
|
||||
void Process::termid(char* buffer) const
|
||||
{
|
||||
if (m_tty == nullptr)
|
||||
|
||||
@@ -63,6 +63,11 @@ namespace Kernel
|
||||
return (long)res.value();
|
||||
}
|
||||
|
||||
void sys_free(void* ptr)
|
||||
{
|
||||
Process::current().free(ptr);
|
||||
}
|
||||
|
||||
extern "C" long cpp_syscall_handler(int syscall, void* arg1, void* arg2, void* arg3)
|
||||
{
|
||||
Thread::current().set_in_syscall(true);
|
||||
@@ -96,6 +101,9 @@ namespace Kernel
|
||||
case SYS_ALLOC:
|
||||
ret = sys_alloc((size_t)arg1);
|
||||
break;
|
||||
case SYS_FREE:
|
||||
sys_free(arg1);
|
||||
break;
|
||||
default:
|
||||
Kernel::panic("Unknown syscall {}", syscall);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user