forked from Bananymous/banan-os
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:
parent
0deda83d05
commit
2fe9af7165
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue