ZXFoundation™ 26h2
Loading...
Searching...
No Matches
kmalloc.cxxm
Go to the documentation of this file.
1/// SPDX-License-Identifier: Apache-2.0
2/// @file zxfoundation/memory/slub.zcomponent/kmalloc.cxxm
3/// @brief General-purpose kernel memory allocator — kmalloc / kfree.
4
5export module zxfoundation.memory.kmalloc;
6import zxfoundation.memory.slub;
7import zxfoundation.memory.slub.types;
8import zxfoundation.sys.syschk.core;
9import zxfoundation.base.types;
10import zxfoundation.base.config;
11import lib.error;
12import std;
13
14namespace zxfoundation::memory::kmalloc::detail {
15
16 /// @brief Number of size-class caches.
17 no_export constexpr u32 KMALLOC_NUM_SIZES = 13U;
18
19 /// @brief Maximum single-allocation size via kmalloc.
20 no_export constexpr u64 KMALLOC_MAX_SIZE = 32768ULL;
21
22 /// @brief Size of each bucket (powers of two, starting at 8).
23 no_export constexpr u64 g_sizes[KMALLOC_NUM_SIZES] {
24 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768
25 };
26
27 no_export std::array<slub::kmem_cache_ref_active, KMALLOC_NUM_SIZES> g_caches{};
28 no_export bool g_initialized{false};
29
30 /// @brief Names for each size-class cache (diagnostic use only).
31 no_export constexpr const char* g_names[KMALLOC_NUM_SIZES] {
32 "kmalloc-8", "kmalloc-16", "kmalloc-32",
33 "kmalloc-64", "kmalloc-128", "kmalloc-256",
34 "kmalloc-512", "kmalloc-1024", "kmalloc-2048",
35 "kmalloc-4096", "kmalloc-8192", "kmalloc-16384",
36 "kmalloc-32768",
37 };
38
39 /// @brief Return the bucket index for a requested size in O(1) time.
40 [[nodiscard]] no_export constexpr auto bucket_for(u64 size) noexcept -> u32 {
41 if (size <= 8ULL) return 0U;
42 if (size > KMALLOC_MAX_SIZE) return KMALLOC_NUM_SIZES; // sentinel
43 const u32 log2_ceil = 64U - static_cast<u32>(__builtin_clzll(size - 1ULL));
44 return log2_ceil - 3U; // bucket 0 ≡ 2^3 = 8
45 }
46
47} // namespace zxfoundation::memory::kmalloc::detail
48
49export {
50
51namespace zxfoundation::memory::kmalloc {
52
53 /// @brief Create all size-class caches.
54 auto kmalloc_init() noexcept -> void {
55 using namespace detail;
56 if (g_initialized) return;
57
58 for (u32 i = 0; i < KMALLOC_NUM_SIZES; ++i) {
59 auto result = slub::kmem_cache_create(
60 g_names[i],
61 static_cast<u32>(g_sizes[i]),
62 static_cast<u32>(g_sizes[i]), // align = object size (power-of-two)
63 slub::slub_flags::none);
64 if (!result) [[unlikely]]
65 sys::syschk::syschk_fatal(
66 result.error(),
67 "kmalloc_init: failed to create {}",
68 g_names[i]);
69 g_caches[i] = *result;
70 }
71
72 g_initialized = true;
73 }
74
75 /// @brief Allocate at least `size` bytes of kernel memory.
76 /// @param[in] size Requested byte count. Must be > 0 and <= KMALLOC_MAX_SIZE.
77 [[nodiscard]] auto kmalloc(u64 size) noexcept -> void* {
78 using namespace detail;
79 if (!g_initialized || size == 0 || size > KMALLOC_MAX_SIZE)
80 [[unlikely]] return nullptr;
81
82 const u32 idx = bucket_for(size);
83 if (idx >= KMALLOC_NUM_SIZES || !g_caches[idx]) [[unlikely]] return nullptr;
84
85 return slub::kmem_alloc(*g_caches[idx]);
86 }
87
88 /// @brief Typed kmalloc: allocate sizeof(T), aligned to alignof(T).
89 template<typename T>
90 [[nodiscard]] auto kmalloc_t() noexcept -> T* {
91 return static_cast<T*>(kmalloc(sizeof(T)));
92 }
93
94 /// @brief Free a pointer previously returned by kmalloc().
95 auto kfree(void* ptr) noexcept -> void {
96 slub::kmem_free_raw(ptr);
97 }
98
99 /// @brief Typed kfree: calls T::~T() then frees the slab slot.
100 template<typename T>
101 auto kfree_t(T* ptr) noexcept -> void {
102 if (ptr) {
103 ptr->~T();
104 slub::kmem_free_raw(static_cast<void*>(ptr));
105 }
106 }
107
108 /// @brief Return the bucket index for a size, or KMALLOC_NUM_SIZES if too large.
109 [[nodiscard]] auto kmalloc_bucket(u64 size) noexcept -> u32 {
110 return detail::bucket_for(size);
111 }
112
113 /// @brief Return the size of the Nth bucket, or 0 if out of range.
114 [[nodiscard]] auto kmalloc_bucket_size(u32 idx) noexcept -> u64 {
115 if (idx >= detail::KMALLOC_NUM_SIZES) return 0;
116 return detail::g_sizes[idx];
117 }
118
119 /// @brief Return the kmem_cache for the Nth bucket, or nullptr.
120 [[nodiscard]] auto kmalloc_cache(u32 idx) noexcept -> slub::kmem_cache_ref_active {
121 using namespace detail;
122 if (!g_initialized || idx >= KMALLOC_NUM_SIZES) return {};
123 return g_caches[idx];
124 }
125
126} // namespace zxfoundation::memory::kmalloc
127
128} // end export
129
130symalias(kmalloc)(u64 size) noexcept -> void* {
131 return zxfoundation::memory::kmalloc::kmalloc(size);
132}
133
134symalias(kfree)(void* ptr) noexcept -> void {
135 zxfoundation::memory::kmalloc::kfree(ptr);
136}
no_export constexpr auto bucket_for(u64 size) noexcept -> u32
Return the bucket index for a requested size in O(1) time.
Definition kmalloc.cxxm:40
no_export constexpr const char * g_names[KMALLOC_NUM_SIZES]
Names for each size-class cache (diagnostic use only).
Definition kmalloc.cxxm:31