3 * @author Lunaixsky (zelong56@gmail.com)
4 * @brief A simplified cake(slab) allocator.
5 * P.s. I call it cake as slab sounds quite 'rigid' to me :)
9 * @copyright Copyright (c) 2022
13 #include <klibc/string.h>
14 #include <lunaix/mm/cake.h>
15 #include <lunaix/mm/page.h>
16 #include <lunaix/spike.h>
17 #include <lunaix/syslog.h>
21 #define CACHE_LINE_SIZE 128
23 static struct cake_pile master_pile, fl_pile, cakes;
25 struct llist_header piles = { .next = &piles, .prev = &piles };
28 embedded_pile(struct cake_pile* pile)
30 return !(pile->options & PILE_FL_EXTERN);
34 __alloc_cake_pages(unsigned int cake_pg)
36 struct leaflet* leaflet = alloc_leaflet(count_order(cake_pg));
41 return (void*)vmap(leaflet, KERNEL_DATA);
44 static struct cake_fl*
45 __alloc_fl(piece_t prev_id, piece_t max_len) {
47 struct cake_fl* cake_fl;
49 cake_fl = cake_grab(&fl_pile);
50 for (i = 0, j=prev_id; i < CAKE_FL_MAXLEN && j < max_len; i++, j++)
52 cake_fl->indices[i] = j + 1;
55 for (i -= 1; j == max_len && i < CAKE_FL_SIZE; i++) {
56 cake_fl->indices[i] = EO_FREE_PIECE;
64 __free_fls(struct cake_s* cake) {
66 struct cake_fl *cake_fl, *next;
72 cake_release(&fl_pile, cake_fl);
80 __fl_slot(struct cake_s* cake, piece_t index)
83 struct cake_fl* cake_fl;
84 struct cake_pile* pile;
87 if (embedded_pile(pile)) {
88 return &cake->free_list[index];
93 while (index >= CAKE_FL_MAXLEN)
95 index -= CAKE_FL_MAXLEN;
96 id_acc += CAKE_FL_MAXLEN;
99 cake_fl = cake_fl->next;
103 cake_fl = __alloc_fl(id_acc, pile->pieces_per_cake);
104 cake_fl->next = cake_fl;
107 return &cake_fl->indices[index];
110 static inline struct cake_s*
111 __create_cake_extern(struct cake_pile* pile)
115 cake = cake_grab(&cakes);
116 if (unlikely(!cake)) {
120 cake->first_piece = __alloc_cake_pages(pile->pg_per_cake);
121 cake->fl = __alloc_fl(0, pile->pieces_per_cake);
127 static inline struct cake_s*
128 __create_cake_embed(struct cake_pile* pile)
132 cake = __alloc_cake_pages(pile->pg_per_cake);
133 if (unlikely(!cake)) {
137 u32_t max_piece = pile->pieces_per_cake;
141 cake->first_piece = (void*)((ptr_t)cake + pile->offset);
144 piece_t* free_list = cake->free_list;
145 for (size_t i = 0; i < max_piece - 1; i++) {
146 free_list[i] = i + 1;
148 free_list[max_piece - 1] = EO_FREE_PIECE;
153 static struct cake_s*
154 __new_cake(struct cake_pile* pile)
158 if (embedded_pile(pile)) {
159 cake = __create_cake_embed(pile);
162 cake = __create_cake_extern(pile);
167 llist_append(&pile->free, &cake->cakes);
173 __init_pile(struct cake_pile* pile,
175 unsigned int piece_size,
176 unsigned int pg_per_cake,
183 unsigned int offset = sizeof(long);
186 if ((options & PILE_ALIGN_CACHE)) {
187 // 对齐到128字节缓存行大小,主要用于DMA
188 offset = CACHE_LINE_SIZE;
191 piece_size = ROUNDUP(piece_size, offset);
192 *pile = (struct cake_pile){ .piece_size = piece_size,
195 .pg_per_cake = pg_per_cake };
197 if (!embedded_pile(pile)) {
199 pile->pieces_per_cake = (pg_per_cake * PAGE_SIZE) / piece_size;
202 unsigned int free_list_size;
204 pile->pieces_per_cake
205 = (pg_per_cake * PAGE_SIZE) /
206 (piece_size + sizeof(piece_t));
209 = pile->pieces_per_cake * sizeof(piece_t);
212 = ROUNDUP(sizeof(struct cake_s) + free_list_size, offset);
213 pile->pieces_per_cake
214 -= ICEIL((pile->offset - free_list_size), piece_size);
217 strncpy(pile->pile_name, name, PILE_NAME_MAXLEN);
219 llist_init_head(&pile->free);
220 llist_init_head(&pile->full);
221 llist_init_head(&pile->partial);
222 llist_append(&piles, &pile->piles);
226 __destory_cake(struct cake_s* cake)
228 // Pinkie Pie is going to MAD!
230 struct leaflet* leaflet;
231 struct cake_pile* owner;
236 assert(!cake->used_pieces);
238 llist_delete(&cake->cakes);
239 owner->cakes_count--;
241 if (!embedded_pile(owner)) {
242 page_va = __ptr(cake->first_piece);
244 cake_release(&cakes, cake);
247 page_va = __ptr(cake);
250 _pfn = pfn(vmm_v2p(page_va));
251 leaflet = ppfn_leaflet(_pfn);
252 vunmap(page_va, leaflet);
254 leaflet_return(leaflet);
260 // pinkamina is our master, no one shall precede her.
261 __init_pile(&master_pile, "pinkamina",
262 sizeof(master_pile), 1, 0);
264 __init_pile(&fl_pile, "gummy", \
265 sizeof(struct cake_fl), 1, 0);
266 __init_pile(&cakes, "cakes", \
267 sizeof(struct cake_s), 1, 0);
271 cake_new_pile(char* name,
272 unsigned int piece_size,
273 unsigned int pg_per_cake,
276 struct cake_pile* pile = (struct cake_pile*)cake_grab(&master_pile);
278 // must aligned to napot order!
279 assert(is_pot(pg_per_cake));
281 __init_pile(pile, name, piece_size, pg_per_cake, options);
287 cake_set_constructor(struct cake_pile* pile, pile_cb ctor)
293 cake_grab(struct cake_pile* pile)
295 struct cake_s *pos, *n;
296 if (!llist_empty(&pile->partial)) {
297 pos = list_entry(pile->partial.next, typeof(*pos), cakes);
298 } else if (llist_empty(&pile->free)) {
299 pos = __new_cake(pile);
301 pos = list_entry(pile->free.next, typeof(*pos), cakes);
308 piece_t found_index, *fl_slot;
310 found_index = pos->next_free;
311 fl_slot = __fl_slot(pos, found_index);
313 pos->next_free = *fl_slot;
315 pile->alloced_pieces++;
317 llist_delete(&pos->cakes);
319 fl_slot = __fl_slot(pos, pos->next_free);
320 if (*fl_slot == EO_FREE_PIECE) {
321 llist_append(&pile->full, &pos->cakes);
323 llist_append(&pile->partial, &pos->cakes);
327 (void*)(__ptr(pos->first_piece) + found_index * pile->piece_size);
330 pile->ctor(pile, piece);
337 cake_release(struct cake_pile* pile, void* area)
340 size_t dsize = 0, maybe_index;
343 struct cake_s *pos, *n;
344 struct llist_header* hdrs[2] = { &pile->full, &pile->partial };
346 for (size_t i = 0; i < 2; i++) {
347 llist_for_each(pos, n, hdrs[i], cakes)
349 if (pos->first_piece > area) {
353 dsize = __ptr(area - pos->first_piece);
354 maybe_index = dsize / pile->piece_size;
356 if (maybe_index < pile->pieces_per_cake) {
357 piece_index = (piece_t)maybe_index;
366 assert(!(dsize % pile->piece_size));
368 assert_msg(piece_index != pos->next_free, "double free");
370 fl_slot = __fl_slot(pos, piece_index);
371 *fl_slot = pos->next_free;
372 pos->next_free = piece_index;
375 pile->alloced_pieces--;
377 llist_delete(&pos->cakes);
378 if (!pos->used_pieces) {
379 llist_append(&pile->free, &pos->cakes);
381 llist_append(&pile->partial, &pos->cakes);
384 *((unsigned int*)area) = DEADCAKE_MARK;
390 cake_ctor_zeroing(struct cake_pile* pile, void* piece)
392 memset(piece, 0, pile->piece_size);
396 __reclaim(struct cake_pile *pile)
398 struct cake_s *pos, *n;
399 llist_for_each(pos, n, &pile->free, cakes)
408 struct cake_pile *pos, *n;
409 llist_for_each(pos, n, &master_pile.piles, piles)