1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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];
|