diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-04-21 23:22:34 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-04-21 23:22:34 +0800 |
| commit | 0a657596e19281f57ae74fd00e38cf25fee4d8cd (patch) | |
| tree | d834c30c05a10905558919070090e4225a17b9a8 /na/mm/slab.h | |
| parent | 04f27cb82d29c980660e485d3358ead9a820d281 (diff) | |
| download | lume-0a657596e19281f57ae74fd00e38cf25fee4d8cd.tar.gz lume-0a657596e19281f57ae74fd00e38cf25fee4d8cd.tar.xz | |
feat: add SLUB allocator implementation with KmemCache management
Diffstat (limited to 'na/mm/slab.h')
| -rw-r--r-- | na/mm/slab.h | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/na/mm/slab.h b/na/mm/slab.h new file mode 100644 index 0000000..716ebe6 --- /dev/null +++ b/na/mm/slab.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +#pragma once + +/* + * SLUB Allocator — module-private header + * + * SLUB = Simple List of Unfull Blocks. + * Metadata lives in Frame descriptors (no per-page Slab header). + * Free object list is embedded inside the objects themselves. + * Per-CPU "active page" eliminates lock contention on the fast path. + * + * Reference: docs/specs/slab.md + */ + +#include <lume/types.h> +#include <lume/config.h> +#include <lume/frame.h> +#include <lume/list.h> +#include <kernel/sync/spinlock.h> + +/* Size classes: 8, 16, 32, 64, 128, 256, 512, 1024, 2048 */ +inline constexpr int kNumSizeClasses = 9; +inline constexpr uint32 kSizeClasses[kNumSizeClasses] = { + 8, 16, 32, 64, 128, 256, 512, 1024, 2048 +}; + +/* Per-CPU active slab page pointer */ +struct PerCpuSlab { + Frame* active; // Currently used slab page (nullptr if none) +}; + +/* + * KmemCache — manages a pool of fixed-size objects. + * + * Lock contract: + * lock_ protects partial_ list only. + * Per-CPU cpu_slab_ access requires interrupts disabled. + * PMM calls happen outside lock_ to avoid lock ordering issues. + */ +class KmemCache { +public: + KmemCache() = default; + + // Explicit init (Placement New / BSS pattern) + void init(const char* name, uint32 obj_size, uint32 obj_align); + + // Allocate one object. Returns nullptr on OOM. + void* alloc(); + + // Free one object back to its owning page. + void free(void* obj); + + const char* name() const { return name_; } + uint32 obj_size() const { return obj_size_; } + +private: + // Get a partially-filled page from the partial list (lock must be held) + Frame* get_partial(); + + // Put a page onto the partial list (lock must be held) + void put_partial(Frame* f); + + // Remove a page from the partial list (lock must be held) + void remove_partial(Frame* f); + + // Allocate a new page from PMM and format it as a slab + Frame* new_slab(); + + Spinlock lock_; // Protects partial_ only + list_node partial_; // Partially-filled slab pages + + PerCpuSlab cpu_slab_[kMaxCpus]; // Per-CPU active page + + const char* name_ = "uninit"; + uint32 obj_size_ = 0; // Aligned object size (bytes) + uint32 obj_align_ = 0; // Alignment requirement + uint32 objs_per_slab_ = 0; // Objects per 4KB page +}; + +/* Global size-class caches */ +extern KmemCache g_size_caches[kNumSizeClasses]; |
