From c6c3a556b332b7d5a1e539f920345e79edb16a31 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 31 May 2020 18:22:23 -0700 Subject: [PATCH] [kernel] Remove explicit allocator passing Many kernel objects had to keep a hold of refrences to allocators in order to pass them on down the call chain. Remove those explicit refrences and use `operator new`, `operator delete`, and define new `kalloc` and `kfree`. Also remove `slab_allocator` and replace it with a new mixin for slab allocation, `slab_allocated`, that overrides `operator new` and `operator free` for its subclass. Remove some no longer used related headers, `buddy_allocator.h` and `address_manager.h` Tags: memory --- src/kernel/device_manager.cpp | 7 +- src/kernel/main.cpp | 6 +- src/kernel/memory_bootstrap.cpp | 8 +- src/kernel/objects/kobject.cpp | 1 - src/kernel/process.cpp | 5 +- src/kernel/scheduler.cpp | 13 +- src/kernel/scheduler.h | 7 +- src/libraries/initrd/include/initrd/initrd.h | 2 +- src/libraries/initrd/initrd.cpp | 3 +- .../kutil/include/kutil/address_manager.h | 15 - src/libraries/kutil/include/kutil/avl_tree.h | 18 +- .../kutil/include/kutil/buddy_allocator.h | 302 ------------------ src/libraries/kutil/include/kutil/memory.h | 13 +- .../kutil/include/kutil/slab_allocated.h | 52 +++ .../kutil/include/kutil/slab_allocator.h | 72 ----- src/libraries/kutil/include/kutil/vector.h | 31 +- src/libraries/kutil/include/kutil/vm_space.h | 6 +- src/libraries/kutil/vm_space.cpp | 23 +- src/tests/address_manager.cpp | 78 ----- 19 files changed, 125 insertions(+), 537 deletions(-) delete mode 100644 src/libraries/kutil/include/kutil/address_manager.h delete mode 100644 src/libraries/kutil/include/kutil/buddy_allocator.h create mode 100644 src/libraries/kutil/include/kutil/slab_allocated.h delete mode 100644 src/libraries/kutil/include/kutil/slab_allocator.h delete mode 100644 src/tests/address_manager.cpp diff --git a/src/kernel/device_manager.cpp b/src/kernel/device_manager.cpp index 2ae96dd..92e3ea2 100644 --- a/src/kernel/device_manager.cpp +++ b/src/kernel/device_manager.cpp @@ -60,12 +60,7 @@ void irq4_callback(void *) device_manager::device_manager(const void *root_table, kutil::allocator &alloc) : - m_lapic(nullptr), - m_ioapics(alloc), - m_pci(alloc), - m_devices(alloc), - m_irqs(alloc), - m_blockdevs(alloc) + m_lapic(nullptr) { kassert(root_table != 0, "ACPI root table pointer is null."); diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index aca26fc..645d162 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -99,13 +99,13 @@ kernel_main(args::header *header) log::debug(logs::boot, "Runtime service is at: %016lx", header->runtime_services); // Load the module tagged as initrd - kutil::vector initrds(heap); + kutil::vector initrds; for (unsigned i = 0; i < header->num_modules; ++i) { args::module &mod = header->modules[i]; if (mod.type != args::mod_type::initrd) continue; - initrd::disk &ird = initrds.emplace(mod.location, heap); + initrd::disk &ird = initrds.emplace(mod.location); log::info(logs::boot, "initrd loaded with %d files.", ird.files().count()); for (auto &f : ird.files()) log::info(logs::boot, " %s%s (%d bytes).", f.executable() ? "*" : "", f.name(), f.size()); @@ -159,7 +159,7 @@ kernel_main(args::header *header) devices->get_lapic()->calibrate_timer(); syscall_enable(); - scheduler *sched = new (&scheduler::get()) scheduler(devices->get_lapic(), heap); + scheduler *sched = new (&scheduler::get()) scheduler(devices->get_lapic()); sched->create_kernel_task(-1, logger_task); diff --git a/src/kernel/memory_bootstrap.cpp b/src/kernel/memory_bootstrap.cpp index 4e413f9..150596e 100644 --- a/src/kernel/memory_bootstrap.cpp +++ b/src/kernel/memory_bootstrap.cpp @@ -31,6 +31,11 @@ void * operator new [] (size_t size) { return g_kernel_heap.allocate(size) void operator delete (void *p) noexcept { return g_kernel_heap.free(p); } void operator delete [] (void *p) noexcept { return g_kernel_heap.free(p); } +namespace kutil { +void * kalloc(size_t size) { return g_kernel_heap.allocate(size); } +void kfree(void *p) { return g_kernel_heap.free(p); } +} + void walk_page_table( page_table *table, page_table::level level, @@ -90,8 +95,7 @@ memory_initialize(args::header *kargs) new (&g_kernel_space) kutil::vm_space { kernel_offset, - (page_offset-kernel_offset), - g_kernel_heap}; + (page_offset-kernel_offset)}; uintptr_t current_start = 0; diff --git a/src/kernel/objects/kobject.cpp b/src/kernel/objects/kobject.cpp index 64bc8af..a8662a1 100644 --- a/src/kernel/objects/kobject.cpp +++ b/src/kernel/objects/kobject.cpp @@ -12,7 +12,6 @@ static j6_koid_t next_koid; kobject::kobject(type t, j6_signal_t signals) : m_koid(koid_generate(t)), m_signals(signals), - m_observers(g_kernel_heap), m_handle_count(0) {} diff --git a/src/kernel/process.cpp b/src/kernel/process.cpp index 79dcbe3..de3995d 100644 --- a/src/kernel/process.cpp +++ b/src/kernel/process.cpp @@ -1,4 +1,4 @@ -#include "kutil/heap_allocator.h" +#include "kutil/assert.h" #include "cpu.h" #include "debug.h" #include "log.h" @@ -6,7 +6,6 @@ #include "scheduler.h" extern "C" void task_fork_return_thunk(); -extern kutil::heap_allocator g_kernel_heap; // TODO: this is a bad hack to get access to the heap void process::exit(uint32_t code) @@ -68,7 +67,7 @@ process::setup_kernel_stack() constexpr unsigned null_frame_entries = 2; constexpr size_t null_frame_size = null_frame_entries * sizeof(uint64_t); - void *stack_bottom = g_kernel_heap.allocate(initial_stack_size); + void *stack_bottom = kutil::kalloc(initial_stack_size); kutil::memset(stack_bottom, 0, initial_stack_size); log::debug(logs::memory, "Created kernel stack at %016lx size 0x%lx", diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index 802a8fc..3a33ea6 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -16,7 +16,7 @@ using memory::initial_stack; -scheduler scheduler::s_instance(nullptr, kutil::allocator::invalid); +scheduler scheduler::s_instance(nullptr); const uint64_t rflags_noint = 0x002; const uint64_t rflags_int = 0x202; @@ -28,12 +28,11 @@ extern "C" { extern uint64_t idle_stack_end; -scheduler::scheduler(lapic *apic, kutil::allocator &alloc) : +scheduler::scheduler(lapic *apic) : m_apic(apic), - m_next_pid(1), - m_process_allocator(alloc) + m_next_pid(1) { - auto *idle = m_process_allocator.pop(); + auto *idle = new process_node; uint8_t last_pri = num_priorities - 1; // The kernel idle task, also the thread we're in now @@ -121,7 +120,7 @@ scheduler::create_process(pid_t pid) { kassert(pid <= 0, "Cannot specify a positive pid in create_process"); - auto *proc = m_process_allocator.pop(); + auto *proc = new process_node; proc->pid = pid ? pid : m_next_pid++; proc->priority = default_priority; return proc; @@ -233,7 +232,7 @@ void scheduler::prune(uint64_t now) if (parent && parent->wake_on_child(remove)) { m_blocked.remove(parent); m_runlists[parent->priority].push_front(parent); - m_process_allocator.push(remove); + delete remove; } else { m_exited.push_back(remove); } diff --git a/src/kernel/scheduler.h b/src/kernel/scheduler.h index c88faf9..245673f 100644 --- a/src/kernel/scheduler.h +++ b/src/kernel/scheduler.h @@ -4,7 +4,6 @@ #include #include "kutil/allocator.h" -#include "kutil/slab_allocator.h" #include "process.h" class lapic; @@ -31,8 +30,7 @@ public: /// Constructor. /// \arg apic Pointer to the local APIC object - /// \arg alloc Allocator to use for TCBs - scheduler(lapic *apic, kutil::allocator &alloc); + scheduler(lapic *apic); /// Create a new process from a program image in memory. /// \arg name Name of the program image @@ -86,9 +84,6 @@ private: uint32_t m_next_pid; uint32_t m_tick_count; - using process_slab = kutil::slab_allocator; - process_slab m_process_allocator; - process_node *m_current; process_list m_runlists[num_priorities]; process_list m_blocked; diff --git a/src/libraries/initrd/include/initrd/initrd.h b/src/libraries/initrd/include/initrd/initrd.h index 5a48844..ed8a676 100644 --- a/src/libraries/initrd/include/initrd/initrd.h +++ b/src/libraries/initrd/include/initrd/initrd.h @@ -49,7 +49,7 @@ class disk public: /// Constructor. /// \arg start The start of the initrd in memory - disk(const void *start, kutil::allocator &alloc); + disk(const void *start); /// Get the vector of files on the disk const kutil::vector & files() const { return m_files; } diff --git a/src/libraries/initrd/initrd.cpp b/src/libraries/initrd/initrd.cpp index dad412d..bfd2fd7 100644 --- a/src/libraries/initrd/initrd.cpp +++ b/src/libraries/initrd/initrd.cpp @@ -23,8 +23,7 @@ file::executable() const { } -disk::disk(const void *start, kutil::allocator &alloc) : - m_files(alloc) +disk::disk(const void *start) { auto *header = reinterpret_cast(start); size_t length = header->length; diff --git a/src/libraries/kutil/include/kutil/address_manager.h b/src/libraries/kutil/include/kutil/address_manager.h deleted file mode 100644 index b2c21c1..0000000 --- a/src/libraries/kutil/include/kutil/address_manager.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -/// \file address_manager.h -/// The virtual memory address space manager - -#include "kutil/buddy_allocator.h" - -namespace kutil { - -using address_manager = - buddy_allocator< - 12, // Min allocation: 4KiB - 36 // Max allocation: 64GiB - >; - -} //namespace kutil diff --git a/src/libraries/kutil/include/kutil/avl_tree.h b/src/libraries/kutil/include/kutil/avl_tree.h index 80ac5a6..39d95d0 100644 --- a/src/libraries/kutil/include/kutil/avl_tree.h +++ b/src/libraries/kutil/include/kutil/avl_tree.h @@ -5,6 +5,7 @@ #include #include #include "kutil/assert.h" +#include "kutil/slab_allocated.h" namespace kutil { @@ -14,7 +15,8 @@ template class avl_tree; /// A node in a `avl_tree` template class avl_node : - public T + public T, + public slab_allocated> { public: using item_type = T; @@ -151,7 +153,7 @@ private: return existing; } - static node_type * remove(node_type *existing, node_type *subtrahend, allocator &alloc) + static node_type * remove(node_type *existing, node_type *subtrahend) { if (existing == nullptr) return existing; @@ -170,7 +172,7 @@ private: *existing = *temp; } - alloc.free(temp); + delete temp; } else { // Both children exist, find next node node_type *temp = existing->m_right; @@ -178,12 +180,12 @@ private: temp = temp->m_left; *existing = *temp; - existing->m_right = remove(existing->m_right, temp, alloc); + existing->m_right = remove(existing->m_right, temp); } } else if (existing->compare(subtrahend) < 0) { - existing->m_left = remove(existing->m_left, subtrahend, alloc); + existing->m_left = remove(existing->m_left, subtrahend); } else { - existing->m_right = remove(existing->m_right, subtrahend, alloc); + existing->m_right = remove(existing->m_right, subtrahend); } if (!existing) @@ -232,8 +234,8 @@ public: inline node_type * root() { return m_root; } inline unsigned count() const { return m_count; } - inline void remove(node_type *subtrahend, allocator &alloc) { - m_root = node_type::remove(m_root, subtrahend, alloc); + inline void remove(node_type *subtrahend) { + m_root = node_type::remove(m_root, subtrahend); m_count--; } diff --git a/src/libraries/kutil/include/kutil/buddy_allocator.h b/src/libraries/kutil/include/kutil/buddy_allocator.h deleted file mode 100644 index 1ff09e6..0000000 --- a/src/libraries/kutil/include/kutil/buddy_allocator.h +++ /dev/null @@ -1,302 +0,0 @@ -#pragma once -/// \file buddy_allocator.h -/// Helper base class for buddy allocators with external node storage. - -#include -#include -#include "kutil/assert.h" -#include "kutil/linked_list.h" -#include "kutil/slab_allocator.h" - -namespace kutil { - -struct buddy_region; - - -template< - unsigned size_min, - unsigned size_max, - typename region_type = buddy_region> -class buddy_allocator -{ -public: - using region_node = list_node; - using region_list = linked_list; - - static const size_t min_alloc = (1 << size_min); - static const size_t max_alloc = (1 << size_max); - - /// Default constructor creates an invalid object. - buddy_allocator() : m_alloc(allocator::invalid) {} - - /// Constructor. - /// \arg alloc Allocator to use for region nodes - buddy_allocator(allocator &alloc) : m_alloc(alloc) {} - - /// Move-like constructor. Takes ownership of existing regions. - buddy_allocator(buddy_allocator &&other, allocator &alloc) : - m_alloc(alloc) - { - for (unsigned i = 0; i < buckets; ++i) { - m_free[i] = std::move(other.m_free[i]); - m_used[i] = std::move(other.m_used[i]); - } - } - - /// Add address space to be managed. - /// \arg start Initial address in the managed range - /// \arg length Size of the managed range, in bytes - void add_regions(uintptr_t start, size_t length) - { - uintptr_t p = start; - unsigned size = size_max; - - while (size >= size_min) { - size_t chunk_size = 1ull << size; - - while (p + chunk_size <= start + length) { - region_node *r = m_alloc.pop(); - r->size = size_max; - r->address = p; - - free_bucket(size).sorted_insert(r); - p += chunk_size; - } - - size--; - } - } - - /// Allocate address space from the managed area. - /// \arg length The amount of memory to allocate, in bytes - /// \returns The address of the start of the allocated area, or 0 on - /// failure - uintptr_t allocate(size_t length) - { - unsigned size = size_min; - while ((1ull << size) < length) - if (size++ == size_max) - return 0; - - unsigned request = size; - while (free_bucket(request).empty()) - if (request++ == size_max) - return 0; - - region_node *r = nullptr; - while (request > size) { - r = free_bucket(request).pop_front(); - region_node *n = split(r); - request--; - - free_bucket(request).sorted_insert(n); - if (request != size) - free_bucket(request).sorted_insert(r); - } - - if (r == nullptr) r = free_bucket(size).pop_front(); - used_bucket(size).sorted_insert(r); - - return r->address; - } - - /// Mark a region as allocated. - /// \arg start The start of the region - /// \arg length The size of the region, in bytes - /// \returns The address of the start of the allocated area, or 0 on - /// failure. This may be less than `start`. - uintptr_t mark(uintptr_t start, size_t length) - { - uintptr_t end = start + length; - region_node *found = nullptr; - - for (unsigned i = size_max; i >= size_min && !found; --i) { - for (auto *r : free_bucket(i)) { - if (start >= r->address && end <= r->end()) { - free_bucket(i).remove(r); - found = r; - break; - } - } - } - - kassert(found, "buddy_allocator::mark called for unknown region"); - if (!found) - return 0; - - found = maybe_split(found, start, end); - used_bucket(found->size).sorted_insert(found); - return found->address; - } - - /// Mark a region as permanently allocated. The region is not returned, - /// as the block can never be freed. This may remove several smaller - /// regions in order to more closely fit the region described. - /// \arg start The start of the region - /// \arg length The size of the region, in bytes - /// \returns The address of the start of the allocated area, or 0 on - /// failure. This may be less than `start`. - void mark_permanent(uintptr_t start, size_t length) - { - uintptr_t end = start + length; - for (unsigned i = size_max; i >= size_min; --i) { - for (auto *r : free_bucket(i)) { - if (start >= r->address && end <= r->end()) { - free_bucket(i).remove(r); - delete_region(r, start, end); - return; - } - } - } - - kassert(false, "buddy_allocator::mark_permanent called for unknown region"); - } - - /// Free a previous allocation. - /// \arg p An address previously retuned by allocate() - void free(uintptr_t p) - { - region_node *found = find(p, true); - - kassert(found, "buddy_allocator::free called for unknown region"); - if (!found) - return; - - used_bucket(found->size).remove(found); - free_bucket(found->size).sorted_insert(found); - - while (auto *bud = get_buddy(found)) { - region_node *eld = found->elder() ? found : bud; - region_node *other = found->elder() ? bud : found; - - free_bucket(other->size).remove(other); - m_alloc.push(other); - - free_bucket(eld->size).remove(eld); - eld->size++; - free_bucket(eld->size).sorted_insert(eld); - - found = eld; - } - } - - /// Check if an allocation exists - /// \arg addr Address within the managed space - /// \returns True if the address is in a region currently allocated - bool contains(uintptr_t addr) - { - for (unsigned i = size_max; i >= size_min; --i) { - for (auto *r : used_bucket(i)) { - if (r->contains(addr)) - return true; - else if (r->address < addr) - break; - } - } - - return false; - } - -protected: - /// Split a region of the given size into two smaller regions, returning - /// the new latter half - region_node * split(region_node *reg) - { - region_node *other = m_alloc.pop(); - - other->size = --reg->size; - other->address = reg->address + (1ull << reg->size); - return other; - } - - /// Find a node with the given address - region_node * find(uintptr_t p, bool used = true) - { - for (unsigned size = size_max; size >= size_min; --size) { - auto &list = used ? used_bucket(size) : free_bucket(size); - for (auto *f : list) { - if (f->address < p) continue; - if (f->address == p) return f; - break; - } - } - return nullptr; - } - - /// Helper to get the buddy for a node, if it's adjacent - region_node * get_buddy(region_node *r) - { - region_node *b = r->elder() ? r->next() : r->prev(); - if (b && b->address == r->buddy()) - return b; - return nullptr; - } - - region_node * maybe_split(region_node *reg, uintptr_t start, uintptr_t end) - { - while (reg->size > size_min) { - // Split if the request fits in the second half - if (start >= reg->half()) { - region_node *other = split(reg); - free_bucket(reg->size).sorted_insert(reg); - reg = other; - } - - // Split if the request fits in the first half - else if (end <= reg->half()) { - region_node *other = split(reg); - free_bucket(other->size).sorted_insert(other); - } - - // If neither, we've split as much as possible - else break; - } - - return reg; - } - - void delete_region(region_node *reg, uintptr_t start, uintptr_t end) - { - reg = maybe_split(reg, start, end); - - size_t leading = start - reg->address; - size_t trailing = reg->end() - end; - if (leading > (1< (1<end()); - delete_region(tail, tail->address, end); - } else { - m_alloc.push(reg); - } - } - - region_list & used_bucket(unsigned size) { return m_used[size - size_min]; } - region_list & free_bucket(unsigned size) { return m_free[size - size_min]; } - - static const unsigned buckets = (size_max - size_min + 1); - - region_list m_free[buckets]; - region_list m_used[buckets]; - slab_allocator m_alloc; -}; - - -struct buddy_region -{ - inline int compare(const buddy_region *o) const { - return address > o->address ? 1 : \ - address < o->address ? -1 : 0; - } - - inline uintptr_t end() const { return address + (1ull << size); } - inline uintptr_t half() const { return address + (1ull << (size - 1)); } - inline bool contains(uintptr_t p) const { return p >= address && p < end(); } - - inline uintptr_t buddy() const { return address ^ (1ull << size); } - inline bool elder() const { return address < buddy(); } - - uint16_t size; - uintptr_t address; -}; - -} // namespace kutil diff --git a/src/libraries/kutil/include/kutil/memory.h b/src/libraries/kutil/include/kutil/memory.h index f5bbca2..cf767a5 100644 --- a/src/libraries/kutil/include/kutil/memory.h +++ b/src/libraries/kutil/include/kutil/memory.h @@ -6,9 +6,20 @@ void * operator new (size_t, void *p) noexcept; - namespace kutil { +/// Allocate from the default allocator. Note this needs to be +/// implemented by users of the kutil library. +/// \arg size The size in bytes requested +/// \returns A pointer to the newly allocated memory, +/// or nullptr on error +void * kalloc(size_t size); + +/// Free memory allocated by `kalloc`. Note this needs to be +/// implemented by users of the kutil library. +/// \arg p Pointer that was returned from a `kalloc` call +void kfree(void *p); + /// Fill memory with the given value. /// \arg p The beginning of the memory area to fill /// \arg v The byte value to fill memory with diff --git a/src/libraries/kutil/include/kutil/slab_allocated.h b/src/libraries/kutil/include/kutil/slab_allocated.h new file mode 100644 index 0000000..d0be1d6 --- /dev/null +++ b/src/libraries/kutil/include/kutil/slab_allocated.h @@ -0,0 +1,52 @@ +#pragma once +/// \file slab_allocated.h +/// A parent template class for slab-allocated objects + +#include "kernel_memory.h" +#include "kutil/memory.h" +#include "kutil/vector.h" + +namespace kutil { + +template +class slab_allocated +{ +public: + void * operator new(size_t size) + { + kassert(size == sizeof(T), "Slab allocator got wrong size allocation"); + if (s_free.count() == 0) + allocate_chunk(); + + T *item = s_free.pop(); + kutil::memset(item, 0, sizeof(T)); + return item; + } + + void operator delete(void *p) { s_free.append(reinterpret_cast(p)); } + + // TODO: get rid of this terribleness + static void hacky_init_remove_me() { + memset(&s_free, 0, sizeof(s_free)); + } + +private: + static void allocate_chunk() + { + size_t size = N * ::memory::frame_size; + s_free.ensure_capacity(size / sizeof(T)); + + void *memory = kalloc(size); + T *current = reinterpret_cast(memory); + T *end = offset_pointer(current, size); + while (current < end) + s_free.append(current++); + } + + static vector s_free; +}; + +#define DEFINE_SLAB_ALLOCATOR(type, N) \ + template<> ::kutil::vector kutil::slab_allocated::s_free {}; + +} // namespace kutil diff --git a/src/libraries/kutil/include/kutil/slab_allocator.h b/src/libraries/kutil/include/kutil/slab_allocator.h deleted file mode 100644 index 80e1aa6..0000000 --- a/src/libraries/kutil/include/kutil/slab_allocator.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once -/// \file slab_allocator.h -/// A slab allocator and related definitions -#include "kutil/allocator.h" -#include "kutil/assert.h" -#include "kutil/linked_list.h" -#include "kutil/memory.h" - -namespace kutil { - - -/// A slab allocator for small structures kept in a linked list -template -class slab_allocator : - public linked_list, - public allocator -{ -public: - using item_type = list_node; - - /// Default constructor. - /// \arg alloc The allocator to use to allocate chunks. Defaults to malloc(). - slab_allocator(allocator &alloc) : - m_alloc(alloc) {} - - /// Allocator interface implementation - virtual void * allocate(size_t size) override - { - kassert(size == sizeof(T), "Asked slab allocator for wrong size"); - if (size != sizeof(T)) return 0; - return pop(); - } - - /// Allocator interface implementation - virtual void free(void *p) override - { - push(static_cast(p)); - } - - /// Get an item from the cache. May allocate a new chunk if the cache is empty. - /// \returns An allocated element - inline item_type * pop() - { - if (this->empty()) this->allocate_chunk(); - kassert(!this->empty(), "Slab allocator is empty after allocate()"); - item_type *item = this->pop_front(); - kutil::memset(item, 0, sizeof(item_type)); - return item; - } - - /// Return an item to the cache. - /// \arg item A previously allocated element - inline void push(item_type *item) - { - this->push_front(item); - } - -private: - void allocate_chunk() - { - constexpr unsigned count = N / sizeof(item_type); - - void *memory = m_alloc.allocate(N); - item_type *items = reinterpret_cast(memory); - for (size_t i = 0; i < count; ++i) - this->push_back(&items[i]); - } - - allocator& m_alloc; -}; - -} // namespace kutil diff --git a/src/libraries/kutil/include/kutil/vector.h b/src/libraries/kutil/include/kutil/vector.h index 441dbc5..c9152e4 100644 --- a/src/libraries/kutil/include/kutil/vector.h +++ b/src/libraries/kutil/include/kutil/vector.h @@ -15,20 +15,18 @@ class vector { public: /// Default constructor. Creates an empty vector with no capacity. - vector(kutil::allocator &alloc = allocator::invalid) : + vector() : m_size(0), m_capacity(0), - m_elements(nullptr), - m_alloc(alloc) + m_elements(nullptr) {} /// Constructor. Creates an empty array with capacity. /// \arg capacity Initial capacity to allocate - vector(size_t capacity, allocator &alloc) : + vector(size_t capacity) : m_size(0), m_capacity(0), - m_elements(nullptr), - m_alloc(alloc) + m_elements(nullptr) { set_capacity(capacity); } @@ -37,8 +35,7 @@ public: vector(const vector& other) : m_size(0), m_capacity(0), - m_elements(nullptr), - m_alloc(other.m_alloc) + m_elements(nullptr) { set_capacity(other.m_capacity); kutil::memcpy(m_elements, other.m_elements, other.m_size * sizeof(T)); @@ -49,8 +46,7 @@ public: vector(vector&& other) : m_size(other.m_size), m_capacity(other.m_capacity), - m_elements(other.m_elements), - m_alloc(other.m_alloc) + m_elements(other.m_elements) { other.m_size = 0; other.m_capacity = 0; @@ -61,7 +57,7 @@ public: ~vector() { while (m_size) remove(); - m_alloc.free(m_elements); + kfree(m_elements); } /// Get the size of the array. @@ -117,6 +113,14 @@ public: m_elements[m_size].~T(); } + /// Remove an item from the end of the array and return it. + T pop() + { + T temp = m_elements[m_size - 1]; + remove(); + return temp; + } + /// Set the size of the array. Any new items are default constructed. /// Any items past the end are deleted. The array is realloced if needed. /// \arg size The new size @@ -149,7 +153,7 @@ public: /// \arg capacity Number of elements to allocate void set_capacity(size_t capacity) { - T *new_array = m_alloc.allocate(capacity); + T *new_array = reinterpret_cast(kalloc(capacity * sizeof(T))); size_t size = std::min(capacity, m_size); kutil::memcpy(new_array, m_elements, size * sizeof(T)); @@ -158,7 +162,7 @@ public: m_size = size; m_capacity = capacity; - m_alloc.free(m_elements); + kfree(m_elements); m_elements = new_array; } @@ -166,7 +170,6 @@ private: size_t m_size; size_t m_capacity; T *m_elements; - allocator &m_alloc; }; } // namespace kutil diff --git a/src/libraries/kutil/include/kutil/vm_space.h b/src/libraries/kutil/include/kutil/vm_space.h index 601fab8..cf135ae 100644 --- a/src/libraries/kutil/include/kutil/vm_space.h +++ b/src/libraries/kutil/include/kutil/vm_space.h @@ -5,7 +5,6 @@ #include #include "kutil/allocator.h" #include "kutil/avl_tree.h" -#include "kutil/slab_allocator.h" namespace kutil { @@ -39,8 +38,7 @@ public: /// Constructor. Define a range of managed VM space. /// \arg start Starting address of the managed space /// \arg size Size of the managed space, in bytes - /// \arg alloc Allocator to use for tracking objects - vm_space(uintptr_t start, size_t size, kutil::allocator &alloc); + vm_space(uintptr_t start, size_t size); /// Reserve a section of address space. /// \arg start Starting address of reservaion, or 0 for any address @@ -76,8 +74,6 @@ private: node_type * split_out(node_type* node, uintptr_t start, size_t size, vm_state state); node_type * consolidate(node_type* needle); - slab_allocator m_slab; - allocator &m_alloc; tree_type m_ranges; }; diff --git a/src/libraries/kutil/vm_space.cpp b/src/libraries/kutil/vm_space.cpp index ac576be..a4a996c 100644 --- a/src/libraries/kutil/vm_space.cpp +++ b/src/libraries/kutil/vm_space.cpp @@ -8,11 +8,14 @@ namespace kutil { using node_type = kutil::avl_node; using node_vec = kutil::vector; -vm_space::vm_space(uintptr_t start, size_t size, allocator &alloc) : - m_slab(alloc), - m_alloc(alloc) +DEFINE_SLAB_ALLOCATOR(node_type, 1); + +vm_space::vm_space(uintptr_t start, size_t size) { - node_type *node = m_slab.pop(); + // TODO: replace this with real global ctor + slab_allocated::hacky_init_remove_me(); + + node_type *node = new node_type; node->address = start; node->size = size; node->state = vm_state::none; @@ -22,9 +25,7 @@ vm_space::vm_space(uintptr_t start, size_t size, allocator &alloc) : start, start+size); } -vm_space::vm_space() : - m_slab(allocator::invalid), - m_alloc(allocator::invalid) +vm_space::vm_space() { } @@ -77,7 +78,7 @@ vm_space::split_out(node_type *node, uintptr_t start, size_t size, vm_state stat // Split off rest into new node size_t leading = start - node->address; - node_type *next = m_slab.pop(); + node_type *next = new node_type; next->state = state; next->address = start; next->size = node->size - leading; @@ -100,7 +101,7 @@ vm_space::split_out(node_type *node, uintptr_t start, size_t size, vm_state stat size_t trailing = node->size - size; node->size -= trailing; - node_type *next = m_slab.pop(); + node_type *next = new node_type; next->state = old_state; next->address = node->end(); next->size = trailing; @@ -132,7 +133,7 @@ inline void gather(node_type *node, node_vec &vec) node_type * vm_space::consolidate(node_type *needle) { - node_vec nodes(m_ranges.count(), m_alloc); + node_vec nodes(m_ranges.count()); gather(m_ranges.root(), nodes); node_type *prev = nullptr; @@ -150,7 +151,7 @@ vm_space::consolidate(node_type *needle) prev->size += node->size; if (needle == node) needle = prev; - m_ranges.remove(node, m_slab); + m_ranges.remove(node); } else { prev = node; } diff --git a/src/tests/address_manager.cpp b/src/tests/address_manager.cpp deleted file mode 100644 index 9e7ba65..0000000 --- a/src/tests/address_manager.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "kutil/address_manager.h" -#include "kutil/allocator.h" -#include "catch.hpp" - -using namespace kutil; - -static const size_t max_block = 1ull << 36; -static const size_t start = max_block; -static const size_t GB = 1ull << 30; - -class malloc_allocator : - public kutil::allocator -{ -public: - virtual void * allocate(size_t n) override { return malloc(n); } - virtual void free(void *p) override { free(p); } -}; - -TEST_CASE( "Buddy addresses tests", "[address buddy]" ) -{ - malloc_allocator alloc; - address_manager am(alloc); - am.add_regions(start, max_block * 2); - - // Blocks should be: - // 36: 0-64G, 64-128G - - uintptr_t a = am.allocate(0x400); // under min - uintptr_t b = am.allocate(0x400); - CHECK( b == a + address_manager::min_alloc); - - am.free(a); - am.free(b); - - // Should be back to - // 36: 0-64G, 64-128G - - a = am.allocate(max_block); - CHECK(a == start); - am.free(a); - - // Should be back to - // 36: 0-64G, 64-128G - - // This should allocate the 66-68G block, not the - // 66-67G block. - a = am.mark( start + 66 * GB + 0x1000, GB ); - CHECK( a == start + 66 * GB ); - - // Free blocks should be: - // 36: 0-64G - // 35: 96-128G - // 34: 80-96G - // 33: 72-80G - // 32: 68-72G - // 31: 64-66G - - // This should cause a split of the one 31 block, NOT - // be a leftover of the above mark. - b = am.allocate(GB); - CHECK( b == start + 64 * GB ); - am.free(b); - am.free(a); - - // Should be back to - // 36: 0-64G, 64-128G - a = am.allocate(max_block); - b = am.allocate(max_block); - CHECK( b == start + max_block ); - CHECK( a == start ); -}