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