Object Allocator

提供 API,使分配小的 object 的時候可以自動切開一個 page,不用每次都分配以 page 為單位的記憶體

Initialization

include/mm.h

free_list 我那時候不知道在寫什麼… 應該直接用 list_head 就好…

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#define MAX_POOL_PAGES          16

struct free_list {
    struct free_list *next;
};

struct pool_t {
    enum booking_status used;
    int obj_size;
    int obj_per_page;
    int obj_used;
    int page_used;
    uint64_t page_addr[MAX_POOL_PAGES];
    struct free_list* free;
};

src/mm.c

1
struct pool_t obj_allocator[MAX_OBJ_ALLOCTOR_NUM];

Registration

指定 object 的 size 並註冊,會回傳一個 token 供 allocation 時識別

src/mm.c

在要空間前先對 size 做 normalize

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void pool_init(struct pool_t* pool, uint64_t size) {
    pool->obj_size = size;
    pool->obj_per_page = PAGE_SIZE / size;
    pool->page_used = 0;
    pool->obj_used = 0;
    pool->free = NULL;
}

int obj_alloc_register(uint64_t size) {
    if (size >= PAGE_SIZE) {
        uart_printf("Object too large\n");
        return -1;
    }

    // normalize size
    uint64_t size_per_allocator = PAGE_SIZE / MAX_OBJ_ALLOCTOR_NUM;
    uint64_t normalize_block = size / size_per_allocator;
    if (size % size_per_allocator) {
        normalize_block++;
    }
    int normalize_size = normalize_block * size_per_allocator;

    for (int i = 0; i < MAX_OBJ_ALLOCTOR_NUM; i++) {
        if (obj_allocator[i].used == USED && obj_allocator[i].obj_size == normalize_size) {
            return i;
        }
        else if (obj_allocator[i].used == AVAL) {
            obj_allocator[i].used = USED;
            pool_init(&obj_allocator[i], normalize_size);
            return i;
        }
    }

    uart_printf("No avaliable pool for current request\n");
    return -1;
}

Allocation

透過 Token 找到 object pool,若 pool 中有曾經被 free 掉的就直接拿來用,沒有的話從 pool 中計算出一個新的位址並回傳,若 page 數量不夠,透過 buddy system 要一塊 page 補上。

src/mm.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
void* obj_alloc_kernel(int token) {
    int pool_num = token;
    struct pool_t* pool = &obj_allocator[pool_num];

    // reused free obj
    if (pool->free != NULL) {
        struct free_list *obj = pool->free;
        pool->free = pool->free->next;
        return obj;
    }

    // need new page
    if (pool->obj_used >= pool->page_used * pool->obj_per_page) {
        pool->page_addr[pool->page_used] = (uint64_t) buddy_alloc(0);
        pool->page_used++;
    }

    // allocate new obj
    uint64_t addr = pool->page_addr[pool->page_used - 1] + pool->obj_used * pool->obj_size;
    pool->obj_used++;
    return (void*) addr;
}

Free

src/mm.c

1
2
3
4
5
6
7
8
void obj_free(int token, void* virt_addr) {
    int pool_num = token;
    struct pool_t* pool = &obj_allocator[pool_num];
    struct free_list* free_head = pool->free;
    pool->free = (struct free_list*) virt_addr;
    pool->free->next = free_head;
    pool->obj_used--;
}
comments powered by Disqus