1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #pragma once |
4 | |
5 | #include <mos/lib/structures/list.hpp> |
6 | #include <mos/lib/sync/spinlock.hpp> |
7 | #include <mos/string.hpp> |
8 | #include <mos/string_view.hpp> |
9 | #include <mos/syslog/printk.hpp> |
10 | #include <mos/type_utils.hpp> |
11 | #include <stddef.h> |
12 | |
13 | /** |
14 | * @brief initialise the slab allocator |
15 | * |
16 | */ |
17 | void slab_init(); |
18 | |
19 | /** |
20 | * @brief Allocate a block of memory from the slab allocator. |
21 | * |
22 | * @param size |
23 | * @return void* |
24 | */ |
25 | void *slab_alloc(size_t size); |
26 | |
27 | /** |
28 | * @brief Allocate a block of memory from the slab allocator and zero it. |
29 | * |
30 | * @param nmemb |
31 | * @param size |
32 | * @return void* |
33 | */ |
34 | void *slab_calloc(size_t nmemb, size_t size); |
35 | |
36 | /** |
37 | * @brief Reallocate a block of memory from the slab allocator. |
38 | * |
39 | * @param addr |
40 | * @param size |
41 | * @return void* |
42 | */ |
43 | void *slab_realloc(void *addr, size_t size); |
44 | |
45 | /** |
46 | * @brief Free a block of memory from the slab allocator. |
47 | * |
48 | * @param addr |
49 | */ |
50 | void slab_free(const void *addr); |
51 | |
52 | struct slab_t |
53 | { |
54 | as_linked_list; |
55 | spinlock_t lock = SPINLOCK_INIT; |
56 | ptr_t first_free = 0; |
57 | size_t ent_size = 0; |
58 | size_t nobjs = 0; |
59 | mos::string_view name = "<unnamed>" ; |
60 | mos::string_view type_name = "<T>" ; |
61 | }; |
62 | |
63 | void slab_register(slab_t *slab); |
64 | void *kmemcache_alloc(slab_t *slab); |
65 | void kmemcache_free(slab_t *slab, const void *addr); |
66 | |
67 | namespace mos |
68 | { |
69 | template<typename T> |
70 | struct Slab : public slab_t |
71 | { |
72 | constexpr Slab(mos::string_view name = T::type_name, size_t size = sizeof(T), mos::string_view type_name = mos::getTypeName<T>()) |
73 | { |
74 | this->name = name; |
75 | this->type_name = type_name; |
76 | this->ent_size = size; |
77 | } |
78 | |
79 | ~Slab() |
80 | { |
81 | pr_emerg("slab: freeing slab for '%s'" , this->type_name.data()); |
82 | } |
83 | |
84 | template<typename... Args> |
85 | T *create(Args &&...args) |
86 | { |
87 | if (!registered) |
88 | slab_register(this), registered = true; |
89 | |
90 | const auto ptr = kmemcache_alloc(this); |
91 | new (ptr) T(std::forward<Args>(args)...); |
92 | return static_cast<T *>(ptr); |
93 | } |
94 | |
95 | size_t size() |
96 | { |
97 | return ent_size; |
98 | } |
99 | |
100 | private: |
101 | bool registered = false; |
102 | }; |
103 | } // namespace mos |
104 | |