Compare commits

..

8 Commits

Author SHA1 Message Date
4081186b27
Heap: Rewrite kmalloc to use Option<HeapBlock*> instead of nullable pointers to iterate over the heap
All checks were successful
continuous-integration/drone/push Build is passing
At some point, this should be done inside LinkedList itself, but we have no such thing as break in for_each().
It's iterate over everything or nothing.

This also requires operator= in Option, might be also added to Result in the future.
2022-12-30 19:02:25 +01:00
3a3968b268
Result: Add nonnull_or_error() 2022-12-30 18:46:27 +01:00
973e39a255
LinkedList: Move nonnull_or_empty_option to Option.h so everyone can use it 2022-12-30 18:46:18 +01:00
28f53f9ccf
LinkedList: Rename the nonnull_or_error() helper to a more accurate nonnull_or_empty_option() 2022-12-30 18:44:37 +01:00
1f36ecd044
LinkedList: Make expect_first() and expect_last() show a more accurate error description on panic
Instead of showing a generic "Option::value() called on an empty Option" with no useful source location,
you will get something like "check failed: m_start_node at LinkedList.h:139"
2022-12-30 18:43:39 +01:00
24773fbece
kernel/main: Remove reference to 'extern const BOOTBOOT bootboot' 2022-12-30 18:38:50 +01:00
74aa30a44f
Init: Call efficient_halt() on magic number mismatch instead of busy-looping 2022-12-30 18:36:22 +01:00
9569385691
Remove unused include 2022-12-30 18:32:44 +01:00
6 changed files with 84 additions and 49 deletions

View File

@ -15,8 +15,7 @@ void Init::check_magic()
if (memcmp(bootboot.magic, BOOTBOOT_MAGIC, 4)) if (memcmp(bootboot.magic, BOOTBOOT_MAGIC, 4))
{ {
kerrorln("ERROR: Invalid magic value from bootloader"); kerrorln("ERROR: Invalid magic value from bootloader");
for (;;) CPU::efficient_halt();
;
} }
} }

View File

@ -5,19 +5,15 @@
#include "arch/MMU.h" #include "arch/MMU.h"
#include "arch/Timer.h" #include "arch/Timer.h"
#include "boot/Init.h" #include "boot/Init.h"
#include "boot/bootboot.h"
#include "config.h" #include "config.h"
#include "memory/Heap.h" #include "memory/Heap.h"
#include "memory/KernelVM.h" #include "memory/KernelVM.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
#include <luna/CString.h> #include <luna/CString.h>
#include <luna/CircularQueue.h>
#include <luna/Result.h> #include <luna/Result.h>
#include <luna/Units.h> #include <luna/Units.h>
extern const BOOTBOOT bootboot;
void heap_thread() void heap_thread()
{ {
CPU::disable_interrupts(); CPU::disable_interrupts();

View File

@ -199,45 +199,50 @@ Result<void*> kmalloc(usize size, bool should_scrub)
heap.append(block); heap.append(block);
} }
HeapBlock* block = heap.expect_first(); Option<HeapBlock*> block = heap.first();
while (block) while (block.has_value())
{ {
HeapBlock* const current = block.value();
// Trying to find a free block... // Trying to find a free block...
if (is_block_free(block)) if (is_block_free(current))
{ {
if (block->full_size < size) if (current->full_size < size)
{ {
block = heap.next(block).value_or(nullptr); block = heap.next(current);
continue; continue;
} }
break; // We found a free block that's big enough!! break; // We found a free block that's big enough!!
} }
auto rc = split(block, size); auto rc = split(current, size);
if (rc.has_value()) if (rc.has_value())
{ {
block = rc.value(); // We managed to get a free block from a larger used block!! block = rc.value(); // We managed to get a free block from a larger used block!!
break; break;
} }
block = heap.next(block).value_or(nullptr); block = heap.next(current);
} }
if (!block) // No free blocks, let's allocate a new one if (!block.has_value()) // No free blocks, let's allocate a new one
{ {
usize pages = get_pages_for_allocation(size + sizeof(HeapBlock)); usize pages = get_pages_for_allocation(size + sizeof(HeapBlock));
block = TRY(allocate_pages(pages)); HeapBlock* const current = TRY(allocate_pages(pages));
block->full_size = (pages * ARCH_PAGE_SIZE) - sizeof(HeapBlock); current->full_size = (pages * ARCH_PAGE_SIZE) - sizeof(HeapBlock);
block->magic = BLOCK_MAGIC; current->magic = BLOCK_MAGIC;
block->status = BLOCK_START_MEM | BLOCK_END_MEM; current->status = BLOCK_START_MEM | BLOCK_END_MEM;
heap.append(block); heap.append(current);
block = current;
} }
block->req_size = size; HeapBlock* const current = block.value();
block->status |= BLOCK_USED;
if (should_scrub) { memset(get_pointer_from_heap_block(block), KMALLOC_SCRUB_BYTE, size); } current->req_size = size;
current->status |= BLOCK_USED;
return get_pointer_from_heap_block(block); if (should_scrub) { memset(get_pointer_from_heap_block(current), KMALLOC_SCRUB_BYTE, size); }
return get_pointer_from_heap_block(current);
} }
Result<void> kfree(void* ptr) Result<void> kfree(void* ptr)
@ -361,24 +366,25 @@ void dump_heap_usage()
} }
usize alloc_total = 0; usize alloc_total = 0;
usize alloc_used = 0; usize alloc_used = 0;
HeapBlock* block = heap.expect_first(); auto block = heap.first();
while (block) while (block.has_value())
{ {
if (is_block_free(block)) HeapBlock* current = block.value();
if (is_block_free(current))
{ {
kdbgln("- Available block (%p), of size %zu (%s%s)", (void*)block, block->full_size, kdbgln("- Available block (%p), of size %zu (%s%s)", (void*)current, current->full_size,
block->status & BLOCK_START_MEM ? "b" : "-", block->status & BLOCK_END_MEM ? "e" : "-"); current->status & BLOCK_START_MEM ? "b" : "-", current->status & BLOCK_END_MEM ? "e" : "-");
alloc_total += block->full_size + sizeof(HeapBlock); alloc_total += current->full_size + sizeof(HeapBlock);
} }
else else
{ {
kdbgln("- Used block (%p), of size %zu, of which %zu bytes are being used (%s%s)", (void*)block, kdbgln("- Used block (%p), of size %zu, of which %zu bytes are being used (%s%s)", (void*)current,
block->full_size, block->req_size, block->status & BLOCK_START_MEM ? "b" : "-", current->full_size, current->req_size, current->status & BLOCK_START_MEM ? "b" : "-",
block->status & BLOCK_END_MEM ? "e" : "-"); current->status & BLOCK_END_MEM ? "e" : "-");
alloc_total += block->full_size + sizeof(HeapBlock); alloc_total += current->full_size + sizeof(HeapBlock);
alloc_used += block->req_size; alloc_used += current->req_size;
} }
block = heap.next(block).value_or(nullptr); block = heap.next(current);
} }
kdbgln("-- Total memory allocated for heap: %zu bytes", alloc_total); kdbgln("-- Total memory allocated for heap: %zu bytes", alloc_total);

View File

@ -2,13 +2,6 @@
#include <luna/Option.h> #include <luna/Option.h>
#include <luna/TypeTraits.h> #include <luna/TypeTraits.h>
template <typename T> inline Option<T*> nonnull_or_error(T* ptr)
{
if (ptr == nullptr) return {};
else
return ptr;
}
template <typename T> class LinkedList; template <typename T> class LinkedList;
template <typename T> class LinkedListNode template <typename T> class LinkedListNode
@ -131,32 +124,34 @@ template <typename T> class LinkedList
Option<T*> first() Option<T*> first()
{ {
return nonnull_or_error((T*)m_start_node); return nonnull_or_empty_option((T*)m_start_node);
} }
T* expect_first() T* expect_first()
{ {
return first().value(); check(m_start_node);
return (T*)m_start_node;
} }
Option<T*> last() Option<T*> last()
{ {
return nonnull_or_error((T*)m_end_node); return nonnull_or_empty_option((T*)m_end_node);
} }
T* expect_last() T* expect_last()
{ {
return last().value(); check(m_end_node);
return (T*)m_end_node;
} }
Option<T*> next(T* item) Option<T*> next(T* item)
{ {
return nonnull_or_error((T*)extract_node(item)->get_next()); return nonnull_or_empty_option((T*)extract_node(item)->get_next());
} }
Option<T*> previous(T* item) Option<T*> previous(T* item)
{ {
return nonnull_or_error((T*)extract_node(item)->get_last()); return nonnull_or_empty_option((T*)extract_node(item)->get_last());
} }
// Iterates over the elements of the LinkedList from start to end, calling callback for every element. // Iterates over the elements of the LinkedList from start to end, calling callback for every element.

View File

@ -30,6 +30,31 @@ template <typename T> class Option
if (m_has_value) { m_storage.store_moved_reference(move(other.m_storage.fetch_reference())); } if (m_has_value) { m_storage.store_moved_reference(move(other.m_storage.fetch_reference())); }
} }
Option<T>& operator=(const Option<T>& other)
{
if (this == &other) return *this;
if (m_has_value) m_storage.destroy();
m_has_value = other.m_has_value;
if (m_has_value) { m_storage.store_reference(other.m_storage.fetch_reference()); }
return *this;
}
Option<T>& operator=(Option<T>&& other)
{
if (this == &other) return *this;
if (m_has_value) m_storage.destroy();
m_has_value = other.m_has_value;
other.m_has_value = false;
if (m_has_value) { m_storage.store_moved_reference(move(other.m_storage.fetch_reference())); }
return *this;
}
Option() : m_has_value(false) Option() : m_has_value(false)
{ {
} }
@ -143,3 +168,10 @@ template <typename T> class Option
Storage m_storage; Storage m_storage;
bool m_has_value { false }; bool m_has_value { false };
}; };
template <typename T> inline Option<T*> nonnull_or_empty_option(T* ptr)
{
if (ptr == nullptr) return {};
else
return ptr;
}

View File

@ -202,3 +202,10 @@ template <> class Result<void>
if (!_expr_rc.has_value()) return _expr_rc.release_error(); \ if (!_expr_rc.has_value()) return _expr_rc.release_error(); \
_expr_rc.release_value(); \ _expr_rc.release_value(); \
}) })
template <typename T> inline Result<T*> nonnull_or_error(T* ptr, int error)
{
if (ptr == nullptr) return err(error);
else
return ptr;
}