aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64/src/memory/heap
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/src/memory/heap')
-rw-r--r--arch/x86_64/src/memory/heap/user_heap_allocator.cpp80
1 files changed, 40 insertions, 40 deletions
diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp
index f3fe1c2..427a68a 100644
--- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp
+++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp
@@ -1,8 +1,6 @@
#include "arch/memory/heap/user_heap_allocator.hpp"
#include "arch/context_switching/syscall/main.hpp"
-#include "arch/exception_handling/assert.hpp"
-#include "arch/exception_handling/panic.hpp"
#include <algorithm>
@@ -20,24 +18,10 @@ namespace teachos::arch::memory::heap
while (current != nullptr)
{
- // TODO: Can not access current pointer. Results in a General Protection Fault?
- if (current->size == total_size)
+ auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size);
+ if (memory.has_value())
{
- auto const memory_address = remove_free_memory_block(previous, current);
- new (memory_address) std::size_t(total_size);
- mutex.unlock();
- return reinterpret_cast<void *>(reinterpret_cast<std::size_t>(memory_address) + sizeof(std::size_t));
- }
- else if (current->size >= total_size + min_allocatable_size())
- {
- // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards
- // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if
- // the total size was less and simply deallocate it as well
- auto const max_size = std::max(total_size, min_allocatable_size());
- auto const memory_address = split_free_memory_block(previous, current, max_size);
- new (memory_address) std::size_t(max_size);
- mutex.unlock();
- return reinterpret_cast<void *>(reinterpret_cast<std::size_t>(memory_address) + sizeof(std::size_t));
+ return memory.value();
}
previous = current;
@@ -48,27 +32,17 @@ namespace teachos::arch::memory::heap
if (current != nullptr)
{
- if (current->size == total_size)
- {
- auto const memory_address = remove_free_memory_block(previous, current);
- new (memory_address) std::size_t(total_size);
- mutex.unlock();
- return reinterpret_cast<void *>(reinterpret_cast<std::size_t>(memory_address) + sizeof(std::size_t));
- }
- else if (current->size >= total_size + min_allocatable_size())
+ auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size);
+ if (memory.has_value())
{
- // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards
- // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if
- // the total size was less and simply deallocate it as well
- auto const max_size = std::max(total_size, min_allocatable_size());
- auto const memory_address = split_free_memory_block(previous, current, max_size);
- new (memory_address) std::size_t(max_size);
- mutex.unlock();
- return reinterpret_cast<void *>(reinterpret_cast<std::size_t>(memory_address) + sizeof(std::size_t));
+ return memory.value();
}
}
- exception_handling::panic("[Linked List Allocator] Out of memory");
+ char constexpr OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory";
+ context_switching::syscall::syscall(context_switching::syscall::type::ASSERT,
+ {false, reinterpret_cast<uint64_t>(&OUT_OF_MEMORY_ERROR_MESSAGE)});
+ return nullptr;
}
auto user_heap_allocator::deallocate(void * pointer) noexcept -> void
@@ -102,6 +76,30 @@ namespace teachos::arch::memory::heap
mutex.unlock();
}
+ auto user_heap_allocator::allocate_into_memory_block_if_big_enough(memory_block * current, memory_block * previous,
+ std::size_t total_size) -> std::optional<void *>
+ {
+ if (current->size == total_size)
+ {
+ auto const memory_address = remove_free_memory_block(previous, current);
+ new (memory_address) std::size_t(total_size);
+ mutex.unlock();
+ return reinterpret_cast<void *>(reinterpret_cast<std::size_t>(memory_address) + sizeof(std::size_t));
+ }
+ else if (current->size >= total_size + min_allocatable_size())
+ {
+ // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards
+ // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if
+ // the total size was less and simply deallocate it as well
+ auto const max_size = std::max(total_size, min_allocatable_size());
+ auto const memory_address = split_free_memory_block(previous, current, max_size);
+ new (memory_address) std::size_t(max_size);
+ mutex.unlock();
+ return reinterpret_cast<void *>(reinterpret_cast<std::size_t>(memory_address) + sizeof(std::size_t));
+ }
+ return std::nullopt;
+ }
+
auto user_heap_allocator::expand_heap_if_full() -> memory_block *
{
auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP);
@@ -180,10 +178,12 @@ namespace teachos::arch::memory::heap
// Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean
// that the block has already been deallocated and we therefore attempted a double free.
- exception_handling::assert(previous_block == nullptr ||
- start_address >=
- (reinterpret_cast<std::size_t>(previous_block) + previous_block->size),
- "[Linked List Allocator] Attempted double free detected");
+ char constexpr DOUBLE_FREE_ERROR_MESSAGE[] = "[Linked List Allocator] Attempted double free detected";
+ context_switching::syscall::syscall(
+ context_switching::syscall::type::ASSERT,
+ {previous_block == nullptr ||
+ start_address >= (reinterpret_cast<std::size_t>(previous_block) + previous_block->size),
+ reinterpret_cast<uint64_t>(&DOUBLE_FREE_ERROR_MESSAGE)});
auto const new_block = new (pointer) memory_block(block_size, next_block);
// If we want to deallocate the first block that is before any other free block, then there exists no previous free