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:
Bananymous 2023-05-07 01:21:50 +03:00
parent 890aa9aa15
commit 12e42f40c5
9 changed files with 112 additions and 45 deletions

View File

@ -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:

View File

@ -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;

View File

@ -8,6 +8,7 @@
#define SYS_SEEK 6
#define SYS_OPEN 7
#define SYS_ALLOC 8
#define SYS_FREE 9
#include <stdint.h>

View File

@ -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];

View File

@ -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)

View File

@ -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);
}

View File

@ -79,7 +79,9 @@ void* calloc(size_t nmemb, size_t size)
return ptr;
}
void free(void*)
void free(void* ptr)
{
if (ptr == nullptr)
return;
syscall(SYS_FREE, ptr);
}

View File

@ -74,6 +74,12 @@ long syscall(long syscall, ...)
ret = Kernel::syscall(SYS_ALLOC, bytes);
break;
}
case SYS_FREE:
{
void* ptr = va_arg(args, void*);
ret = Kernel::syscall(SYS_FREE, ptr);
break;
}
default:
puts("LibC: Unhandeled syscall");
}

View File

@ -3,42 +3,24 @@
int main()
{
void* ptr = malloc(10);
if (ptr == NULL)
for (int i = 0; i < 10; i++)
{
perror("malloc");
return 1;
}
*(int*)ptr = 5;
putc('0' + *(int*)ptr, stdout);
return 0;
FILE* fp = fopen("/boot/grub/grub.cfg", "r");
if (fp == NULL)
{
perror("fopen");
return 1;
}
for (;;)
{
char buffer[128];
size_t nread = fread(buffer, 1, sizeof(buffer) - 1, fp);
if (nread == 0)
int* ptrs[10];
for (int j = 0; j < 10; j++)
{
if (ferror(fp))
perror("fread");
break;
ptrs[j] = malloc(10);
if (ptrs[j] == NULL)
{
perror("malloc");
return 1;
}
*ptrs[j] = j;
putc('0' + *ptrs[j], stdout);
}
buffer[nread] = '\0';
fputs(buffer, stdout);
for (int j = 0; j < 10; j++)
free(ptrs[j]);
putc('\n', stdout);
}
if (fclose(fp) == EOF)
{
perror("fclose");
return 1;
}
return 0;
}