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(); ~FixedWidthAllocator();
vaddr_t allocate(); vaddr_t allocate();
void deallocate(vaddr_t); bool deallocate(vaddr_t);
uint32_t allocation_size() const { return m_allocation_size; } uint32_t allocation_size() const { return m_allocation_size; }
@ -26,8 +26,10 @@ namespace Kernel
{ {
node* prev { nullptr }; node* prev { nullptr };
node* next { 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*); void allocate_page_for_node_if_needed(const node*);
private: private:

View File

@ -57,6 +57,7 @@ namespace Kernel
BAN::ErrorOr<void> set_working_directory(BAN::StringView); BAN::ErrorOr<void> set_working_directory(BAN::StringView);
BAN::ErrorOr<void*> allocate(size_t); BAN::ErrorOr<void*> allocate(size_t);
void free(void*);
void termid(char*) const; void termid(char*) const;

View File

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

View File

@ -87,6 +87,9 @@ namespace Kernel
node* node = m_free_list; node* node = m_free_list;
ASSERT(!node->allocated);
node->allocated = true;
m_free_list = node->next; m_free_list = node->next;
if (m_free_list) if (m_free_list)
m_free_list->prev = nullptr; m_free_list->prev = nullptr;
@ -100,23 +103,50 @@ namespace Kernel
m_allocated++; m_allocated++;
allocate_page_for_node_if_needed(node); 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; if (address % m_allocation_size)
ASSERT_NOT_REACHED(); 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 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)); 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]; vaddr_t page_begin = ((vaddr_t*)m_allocated_pages)[page_index];
ASSERT(page_begin); ASSERT(page_begin);
@ -124,11 +154,38 @@ namespace Kernel
return page_begin + offset * m_allocation_size; 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) void FixedWidthAllocator::allocate_page_for_node_if_needed(const node* node)
{ {
uint32_t index = node - (struct node*)m_nodes_page; 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)); ASSERT(page_index < PAGE_SIZE / sizeof(vaddr_t));
vaddr_t& page_vaddr = ((vaddr_t*)m_allocated_pages)[page_index]; 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); 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 void Process::termid(char* buffer) const
{ {
if (m_tty == nullptr) if (m_tty == nullptr)

View File

@ -63,6 +63,11 @@ namespace Kernel
return (long)res.value(); 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) extern "C" long cpp_syscall_handler(int syscall, void* arg1, void* arg2, void* arg3)
{ {
Thread::current().set_in_syscall(true); Thread::current().set_in_syscall(true);
@ -96,6 +101,9 @@ namespace Kernel
case SYS_ALLOC: case SYS_ALLOC:
ret = sys_alloc((size_t)arg1); ret = sys_alloc((size_t)arg1);
break; break;
case SYS_FREE:
sys_free(arg1);
break;
default: default:
Kernel::panic("Unknown syscall {}", syscall); Kernel::panic("Unknown syscall {}", syscall);
} }

View File

@ -79,7 +79,9 @@ void* calloc(size_t nmemb, size_t size)
return ptr; 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); ret = Kernel::syscall(SYS_ALLOC, bytes);
break; break;
} }
case SYS_FREE:
{
void* ptr = va_arg(args, void*);
ret = Kernel::syscall(SYS_FREE, ptr);
break;
}
default: default:
puts("LibC: Unhandeled syscall"); puts("LibC: Unhandeled syscall");
} }

View File

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