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;
14namespace zxfoundation::memory::kmalloc::detail {
17 no_export
constexpr u32 KMALLOC_NUM_SIZES = 13U;
20 no_export
constexpr u64 KMALLOC_MAX_SIZE = 32768ULL;
23 no_export
constexpr u64 g_sizes[KMALLOC_NUM_SIZES] {
24 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768
27 no_export std::array<slub::kmem_cache_ref_active, KMALLOC_NUM_SIZES> g_caches{};
28 no_export
bool g_initialized{
false};
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",
41 if (size <= 8ULL)
return 0U;
42 if (size > KMALLOC_MAX_SIZE)
return KMALLOC_NUM_SIZES;
43 const u32 log2_ceil = 64U -
static_cast<u32>(__builtin_clzll(size - 1ULL));
44 return log2_ceil - 3U;
51namespace zxfoundation::memory::kmalloc {
54 auto kmalloc_init()
noexcept ->
void {
55 using namespace detail;
56 if (g_initialized)
return;
58 for (u32 i = 0; i < KMALLOC_NUM_SIZES; ++i) {
59 auto result = slub::kmem_cache_create(
61 static_cast<u32>(g_sizes[i]),
62 static_cast<u32>(g_sizes[i]),
63 slub::slub_flags::none);
64 if (!result) [[unlikely]]
65 sys::syschk::syschk_fatal(
67 "kmalloc_init: failed to create {}",
69 g_caches[i] = *result;
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;
82 const u32 idx = bucket_for(size);
83 if (idx >= KMALLOC_NUM_SIZES || !g_caches[idx]) [[unlikely]]
return nullptr;
85 return slub::kmem_alloc(*g_caches[idx]);
90 [[nodiscard]]
auto kmalloc_t()
noexcept -> T* {
91 return static_cast<T*>(kmalloc(
sizeof(T)));
95 auto kfree(
void* ptr)
noexcept ->
void {
96 slub::kmem_free_raw(ptr);
101 auto kfree_t(T* ptr)
noexcept ->
void {
104 slub::kmem_free_raw(
static_cast<
void*>(ptr));
109 [[nodiscard]]
auto kmalloc_bucket(u64 size)
noexcept -> u32 {
110 return detail::bucket_for(size);
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];
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];
130symalias(kmalloc)(u64 size)
noexcept ->
void* {
131 return zxfoundation::memory::kmalloc::kmalloc(size);
134symalias(kfree)(
void* ptr)
noexcept ->
void {
135 zxfoundation::memory::kmalloc::kfree(ptr);
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