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();
|
~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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,42 +3,24 @@
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
void* ptr = malloc(10);
|
for (int i = 0; i < 10; i++)
|
||||||
if (ptr == NULL)
|
|
||||||
{
|
{
|
||||||
perror("malloc");
|
int* ptrs[10];
|
||||||
return 1;
|
for (int j = 0; j < 10; j++)
|
||||||
}
|
|
||||||
*(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)
|
|
||||||
{
|
{
|
||||||
if (ferror(fp))
|
ptrs[j] = malloc(10);
|
||||||
perror("fread");
|
if (ptrs[j] == NULL)
|
||||||
break;
|
{
|
||||||
|
perror("malloc");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*ptrs[j] = j;
|
||||||
|
putc('0' + *ptrs[j], stdout);
|
||||||
}
|
}
|
||||||
buffer[nread] = '\0';
|
for (int j = 0; j < 10; j++)
|
||||||
fputs(buffer, stdout);
|
free(ptrs[j]);
|
||||||
|
putc('\n', stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fclose(fp) == EOF)
|
|
||||||
{
|
|
||||||
perror("fclose");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue