X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/df61e9d0fec3d5e75820e27e7a2459d132364585..a136ca38d83fae60994a54f5da88120e545895e1:/lunaix-os/kernel/mm/cake.c diff --git a/lunaix-os/kernel/mm/cake.c b/lunaix-os/kernel/mm/cake.c index 7e3142b..b1e699f 100644 --- a/lunaix-os/kernel/mm/cake.c +++ b/lunaix-os/kernel/mm/cake.c @@ -2,7 +2,7 @@ * @file cake.c * @author Lunaixsky (zelong56@gmail.com) * @brief A simplified cake(slab) allocator. - * P.s. I call it cake as slab sounds more 'ridge' to me. :) + * P.s. I call it cake as slab sounds quite 'rigid' to me :) * @version 0.1 * @date 2022-07-02 * @@ -12,8 +12,7 @@ #include #include -#include -#include +#include #include #include @@ -21,67 +20,201 @@ LOG_MODULE("CAKE") #define CACHE_LINE_SIZE 128 -struct cake_pile master_pile; +static struct cake_pile master_pile, fl_pile, cakes; struct llist_header piles = { .next = &piles, .prev = &piles }; -void* -__alloc_cake(unsigned int cake_pg) +static inline bool +embedded_pile(struct cake_pile* pile) { - uintptr_t pa = pmm_alloc_cpage(KERNEL_PID, cake_pg, 0); - return vmm_vmap(pa, cake_pg * PG_SIZE, PG_PREM_RW); + return !(pile->options & PILE_FL_EXTERN); } -struct cake_s* -__new_cake(struct cake_pile* pile) +static void* +__alloc_cake_pages(unsigned int cake_pg) +{ + struct leaflet* leaflet = alloc_leaflet(count_order(cake_pg)); + if (!leaflet) { + return NULL; + } + + return (void*)vmap(leaflet, KERNEL_DATA); +} + +static struct cake_fl* +__alloc_fl(piece_t prev_id, piece_t max_len) { + unsigned int i, j; + struct cake_fl* cake_fl; + + cake_fl = cake_grab(&fl_pile); + for (i = 0, j=prev_id; i < CAKE_FL_MAXLEN && j < max_len; i++, j++) + { + cake_fl->indices[i] = j + 1; + } + + for (i -= 1; j == max_len && i < CAKE_FL_SIZE; i++) { + cake_fl->indices[i] = EO_FREE_PIECE; + } + + cake_fl->next = NULL; + return cake_fl; +} + +static void +__free_fls(struct cake_s* cake) { + unsigned int i, j; + struct cake_fl *cake_fl, *next; + + cake_fl = cake->fl; + while (cake_fl) + { + next = cake_fl->next; + cake_release(&fl_pile, cake_fl); + cake_fl = next; + } + + cake->fl = NULL; +} + +static piece_t* +__fl_slot(struct cake_s* cake, piece_t index) { - struct cake_s* cake = __alloc_cake(pile->pg_per_cake); + int id_acc; + struct cake_fl* cake_fl; + struct cake_pile* pile; - int max_piece = pile->pieces_per_cake; + pile = cake->owner; + if (embedded_pile(pile)) { + return &cake->free_list[index]; + } - cake->first_piece = (void*)((uintptr_t)cake + pile->offset); + id_acc = 0; + cake_fl = cake->fl; + while (index >= CAKE_FL_MAXLEN) + { + index -= CAKE_FL_MAXLEN; + id_acc += CAKE_FL_MAXLEN; + + if (cake_fl->next) { + cake_fl = cake_fl->next; + continue; + } + + cake_fl = __alloc_fl(id_acc, pile->pieces_per_cake); + cake_fl->next = cake_fl; + } + + return &cake_fl->indices[index]; +} + +static inline struct cake_s* +__create_cake_extern(struct cake_pile* pile) +{ + struct cake_s* cake; + + cake = cake_grab(&cakes); + if (unlikely(!cake)) { + return NULL; + } + + cake->first_piece = __alloc_cake_pages(pile->pg_per_cake); + cake->fl = __alloc_fl(0, pile->pieces_per_cake); cake->next_free = 0; - piece_index_t* free_list = &cake->free_list; + return cake; +} + +static inline struct cake_s* +__create_cake_embed(struct cake_pile* pile) +{ + struct cake_s* cake; + + cake = __alloc_cake_pages(pile->pg_per_cake); + if (unlikely(!cake)) { + return NULL; + } + + u32_t max_piece = pile->pieces_per_cake; + + assert(max_piece); + + cake->first_piece = (void*)((ptr_t)cake + pile->offset); + cake->next_free = 0; + + piece_t* free_list = cake->free_list; for (size_t i = 0; i < max_piece - 1; i++) { free_list[i] = i + 1; } free_list[max_piece - 1] = EO_FREE_PIECE; + return cake; +} + +static struct cake_s* +__new_cake(struct cake_pile* pile) +{ + struct cake_s* cake; + + if (embedded_pile(pile)) { + cake = __create_cake_embed(pile); + } + else { + cake = __create_cake_extern(pile); + } + + cake->owner = pile; + pile->cakes_count++; llist_append(&pile->free, &cake->cakes); return cake; } -void +static void __init_pile(struct cake_pile* pile, char* name, unsigned int piece_size, unsigned int pg_per_cake, int options) { + if (!pile) { + return; + } + unsigned int offset = sizeof(long); // 默认每块儿蛋糕对齐到地址总线宽度 - if ((options & PILE_CACHELINE)) { + if ((options & PILE_ALIGN_CACHE)) { // 对齐到128字节缓存行大小,主要用于DMA offset = CACHE_LINE_SIZE; } piece_size = ROUNDUP(piece_size, offset); *pile = (struct cake_pile){ .piece_size = piece_size, - .cakes_count = 1, - .pieces_per_cake = - (pg_per_cake * PG_SIZE) / - (piece_size + sizeof(piece_index_t)), + .cakes_count = 0, + .options = options, .pg_per_cake = pg_per_cake }; - unsigned int overhead_size = - sizeof(struct cake_s) + pile->pieces_per_cake * sizeof(piece_index_t); - - pile->offset = ROUNDUP(overhead_size, offset); + if (!embedded_pile(pile)) { + pile->offset = 0; + pile->pieces_per_cake = (pg_per_cake * PAGE_SIZE) / piece_size; + } + else { + unsigned int free_list_size; + + pile->pieces_per_cake + = (pg_per_cake * PAGE_SIZE) / + (piece_size + sizeof(piece_t)); + + free_list_size + = pile->pieces_per_cake * sizeof(piece_t); + + pile->offset + = ROUNDUP(sizeof(struct cake_s) + free_list_size, offset); + pile->pieces_per_cake + -= ICEIL((pile->offset - free_list_size), piece_size); + } - strncpy(&pile->pile_name, name, PILE_NAME_MAXLEN); + strncpy(pile->pile_name, name, PILE_NAME_MAXLEN); llist_init_head(&pile->free); llist_init_head(&pile->full); @@ -89,10 +222,49 @@ __init_pile(struct cake_pile* pile, llist_append(&piles, &pile->piles); } +static void +__destory_cake(struct cake_s* cake) +{ + // Pinkie Pie is going to MAD! + + struct leaflet* leaflet; + struct cake_pile* owner; + pfn_t _pfn; + ptr_t page_va; + + owner = cake->owner; + assert(!cake->used_pieces); + + llist_delete(&cake->cakes); + owner->cakes_count--; + + if (!embedded_pile(owner)) { + page_va = __ptr(cake->first_piece); + __free_fls(cake); + cake_release(&cakes, cake); + } + else { + page_va = __ptr(cake); + } + + _pfn = pfn(vmm_v2p(page_va)); + leaflet = ppfn_leaflet(_pfn); + vunmap(page_va, leaflet); + + leaflet_return(leaflet); +} + void cake_init() { - __init_pile(&master_pile, "pinkamina", sizeof(master_pile), 1, 0); + // pinkamina is our master, no one shall precede her. + __init_pile(&master_pile, "pinkamina", + sizeof(master_pile), 1, 0); + + __init_pile(&fl_pile, "gummy", \ + sizeof(struct cake_fl), 1, 0); + __init_pile(&cakes, "cakes", \ + sizeof(struct cake_s), 1, 0); } struct cake_pile* @@ -103,11 +275,20 @@ cake_new_pile(char* name, { struct cake_pile* pile = (struct cake_pile*)cake_grab(&master_pile); + // must aligned to napot order! + assert(is_pot(pg_per_cake)); + __init_pile(pile, name, piece_size, pg_per_cake, options); return pile; } +void +cake_set_constructor(struct cake_pile* pile, pile_cb ctor) +{ + pile->ctor = ctor; +} + void* cake_grab(struct cake_pile* pile) { @@ -120,27 +301,43 @@ cake_grab(struct cake_pile* pile) pos = list_entry(pile->free.next, typeof(*pos), cakes); } -found: - piece_index_t found_index = pos->next_free; - pos->next_free = pos->free_list[found_index]; + if (!pos) + return NULL; + + void* piece; + piece_t found_index, *fl_slot; + + found_index = pos->next_free; + fl_slot = __fl_slot(pos, found_index); + + pos->next_free = *fl_slot; pos->used_pieces++; pile->alloced_pieces++; llist_delete(&pos->cakes); - if (pos->next_free == EO_FREE_PIECE) { + + fl_slot = __fl_slot(pos, pos->next_free); + if (*fl_slot == EO_FREE_PIECE) { llist_append(&pile->full, &pos->cakes); } else { llist_append(&pile->partial, &pos->cakes); } - return (void*)((uintptr_t)pos->first_piece + - found_index * pile->piece_size); + piece = + (void*)(__ptr(pos->first_piece) + found_index * pile->piece_size); + + if (pile->ctor) { + pile->ctor(pile, piece); + } + + return piece; } int cake_release(struct cake_pile* pile, void* area) { - piece_index_t area_index; + piece_t piece_index; + size_t dsize = 0; struct cake_s *pos, *n; struct llist_header* hdrs[2] = { &pile->full, &pile->partial }; @@ -150,9 +347,9 @@ cake_release(struct cake_pile* pile, void* area) if (pos->first_piece > area) { continue; } - area_index = - (uintptr_t)(area - pos->first_piece) / pile->piece_size; - if (area_index < pile->pieces_per_cake) { + dsize = (ptr_t)(area - pos->first_piece); + piece_index = dsize / pile->piece_size; + if (piece_index < pile->pieces_per_cake) { goto found; } } @@ -161,34 +358,53 @@ cake_release(struct cake_pile* pile, void* area) return 0; found: - pos->free_list[area_index] = pos->next_free; - pos->next_free = area_index; + assert(!(dsize % pile->piece_size)); + + piece_t *fl_slot; + + fl_slot = __fl_slot(pos, piece_index); + *fl_slot = pos->next_free; + pos->next_free = piece_index; + + assert_msg(*fl_slot != pos->next_free, "double free"); + pos->used_pieces--; pile->alloced_pieces--; - llist_delete(pos); + llist_delete(&pos->cakes); if (!pos->used_pieces) { llist_append(&pile->free, &pos->cakes); } else { llist_append(&pile->partial, &pos->cakes); } + *((unsigned int*)area) = DEADCAKE_MARK; + return 1; } void -cake_stats() +cake_ctor_zeroing(struct cake_pile* pile, void* piece) { - kprintf(KDEBUG "

\n"); + memset(piece, 0, pile->piece_size); +} + +static inline void +__reclaim(struct cake_pile *pile) +{ + struct cake_s *pos, *n; + llist_for_each(pos, n, &pile->free, cakes) + { + __destory_cake(pos); + } +} +void +cake_reclaim_freed() +{ struct cake_pile *pos, *n; - llist_for_each(pos, n, &piles, piles) + llist_for_each(pos, n, &master_pile.piles, piles) { - kprintf("%s %d %d %d %d\n", - pos->pile_name, - pos->cakes_count, - pos->pg_per_cake, - pos->pieces_per_cake, - pos->alloced_pieces); + __reclaim(pos); } } \ No newline at end of file