|
|
- #include <pmm.h>
- #include <list.h>
- #include <string.h>
- #include <default_pmm.h>
-
- /* In the first fit algorithm, the allocator keeps a list of free blocks (known as the free list) and,
- on receiving a request for memory, scans along the list for the first block that is large enough to
- satisfy the request. If the chosen block is significantly larger than that requested, then it is
- usually split, and the remainder added to the list as another free block.
- Please see Page 196~198, Section 8.2 of Yan Wei Min's chinese book "Data Structure -- C programming language"
- */
- // LAB2 EXERCISE 1: YOUR CODE
- // you should rewrite functions: default_init,default_init_memmap,default_alloc_pages, default_free_pages.
- /*
- * Details of FFMA
- * (1) Prepare: In order to implement the First-Fit Mem Alloc (FFMA), we should manage the free mem block use some list.
- * The struct free_area_t is used for the management of free mem blocks. At first you should
- * be familiar to the struct list in list.h. struct list is a simple doubly linked list implementation.
- * You should know howto USE: list_init, list_add(list_add_after), list_add_before, list_del, list_next, list_prev
- * Another tricky method is to transform a general list struct to a special struct (such as struct page):
- * you can find some MACRO: le2page (in memlayout.h), (in future labs: le2vma (in vmm.h), le2proc (in proc.h),etc.)
- * (2) default_init: you can reuse the demo default_init fun to init the free_list and set nr_free to 0.
- * free_list is used to record the free mem blocks. nr_free is the total number for free mem blocks.
- * (3) default_init_memmap: CALL GRAPH: kern_init --> pmm_init-->page_init-->init_memmap--> pmm_manager->init_memmap
- * This fun is used to init a free block (with parameter: addr_base, page_number).
- * First you should init each page (in memlayout.h) in this free block, include:
- * p->flags should be set bit PG_property (means this page is valid. In pmm_init fun (in pmm.c),
- * the bit PG_reserved is setted in p->flags)
- * if this page is free and is not the first page of free block, p->property should be set to 0.
- * if this page is free and is the first page of free block, p->property should be set to total num of block.
- * p->ref should be 0, because now p is free and no reference.
- * We can use p->page_link to link this page to free_list, (such as: list_add_before(&free_list, &(p->page_link)); )
- * Finally, we should sum the number of free mem block: nr_free+=n
- * (4) default_alloc_pages: search find a first free block (block size >=n) in free list and reszie the free block, return the addr
- * of malloced block.
- * (4.1) So you should search freelist like this:
- * list_entry_t le = &free_list;
- * while((le=list_next(le)) != &free_list) {
- * ....
- * (4.1.1) In while loop, get the struct page and check the p->property (record the num of free block) >=n?
- * struct Page *p = le2page(le, page_link);
- * if(p->property >= n){ ...
- * (4.1.2) If we find this p, then it' means we find a free block(block size >=n), and the first n pages can be malloced.
- * Some flag bits of this page should be setted: PG_reserved =1, PG_property =0
- * unlink the pages from free_list
- * (4.1.2.1) If (p->property >n), we should re-caluclate number of the the rest of this free block,
- * (such as: le2page(le,page_link))->property = p->property - n;)
- * (4.1.3) re-caluclate nr_free (number of the the rest of all free block)
- * (4.1.4) return p
- * (4.2) If we can not find a free block (block size >=n), then return NULL
- * (5) default_free_pages: relink the pages into free list, maybe merge small free blocks into big free blocks.
- * (5.1) according the base addr of withdrawed blocks, search free list, find the correct position
- * (from low to high addr), and insert the pages. (may use list_next, le2page, list_add_before)
- * (5.2) reset the fields of pages, such as p->ref, p->flags (PageProperty)
- * (5.3) try to merge low addr or high addr blocks. Notice: should change some pages's p->property correctly.
- */
- free_area_t free_area;
-
- #define free_list (free_area.free_list)
- #define nr_free (free_area.nr_free)
-
- static void
- default_init(void) {
- list_init(&free_list);
- nr_free = 0;
- }
-
- static void
- default_init_memmap(struct Page *base, size_t n) {
- assert(n > 0);
- struct Page *p = base;
- for (; p != base + n; p ++) {
- assert(PageReserved(p));
- p->flags = p->property = 0;
- set_page_ref(p, 0);
- }
- base->property = n;
- SetPageProperty(base);
- nr_free += n;
- list_add(&free_list, &(base->page_link));
- }
-
- static struct Page *
- default_alloc_pages(size_t n) {
- assert(n > 0);
- if (n > nr_free) {
- return NULL;
- }
- struct Page *page = NULL;
- list_entry_t *le = &free_list;
- while ((le = list_next(le)) != &free_list) {
- struct Page *p = le2page(le, page_link);
- if (p->property >= n) {
- page = p;
- break;
- }
- }
- if (page != NULL) {
- list_del(&(page->page_link));
- if (page->property > n) {
- struct Page *p = page + n;
- p->property = page->property - n;
- list_add(&free_list, &(p->page_link));
- }
- nr_free -= n;
- ClearPageProperty(page);
- }
- return page;
- }
-
- static void
- default_free_pages(struct Page *base, size_t n) {
- assert(n > 0);
- struct Page *p = base;
- for (; p != base + n; p ++) {
- assert(!PageReserved(p) && !PageProperty(p));
- p->flags = 0;
- set_page_ref(p, 0);
- }
- base->property = n;
- SetPageProperty(base);
- list_entry_t *le = list_next(&free_list);
- while (le != &free_list) {
- p = le2page(le, page_link);
- le = list_next(le);
- if (base + base->property == p) {
- base->property += p->property;
- ClearPageProperty(p);
- list_del(&(p->page_link));
- }
- else if (p + p->property == base) {
- p->property += base->property;
- ClearPageProperty(base);
- base = p;
- list_del(&(p->page_link));
- }
- }
- nr_free += n;
- list_add(&free_list, &(base->page_link));
- }
-
- static size_t
- default_nr_free_pages(void) {
- return nr_free;
- }
-
- static void
- basic_check(void) {
- struct Page *p0, *p1, *p2;
- p0 = p1 = p2 = NULL;
- assert((p0 = alloc_page()) != NULL);
- assert((p1 = alloc_page()) != NULL);
- assert((p2 = alloc_page()) != NULL);
-
- assert(p0 != p1 && p0 != p2 && p1 != p2);
- assert(page_ref(p0) == 0 && page_ref(p1) == 0 && page_ref(p2) == 0);
-
- assert(page2pa(p0) < npage * PGSIZE);
- assert(page2pa(p1) < npage * PGSIZE);
- assert(page2pa(p2) < npage * PGSIZE);
-
- list_entry_t free_list_store = free_list;
- list_init(&free_list);
- assert(list_empty(&free_list));
-
- unsigned int nr_free_store = nr_free;
- nr_free = 0;
-
- assert(alloc_page() == NULL);
-
- free_page(p0);
- free_page(p1);
- free_page(p2);
- assert(nr_free == 3);
-
- assert((p0 = alloc_page()) != NULL);
- assert((p1 = alloc_page()) != NULL);
- assert((p2 = alloc_page()) != NULL);
-
- assert(alloc_page() == NULL);
-
- free_page(p0);
- assert(!list_empty(&free_list));
-
- struct Page *p;
- assert((p = alloc_page()) == p0);
- assert(alloc_page() == NULL);
-
- assert(nr_free == 0);
- free_list = free_list_store;
- nr_free = nr_free_store;
-
- free_page(p);
- free_page(p1);
- free_page(p2);
- }
-
- // LAB2: below code is used to check the first fit allocation algorithm (your EXERCISE 1)
- // NOTICE: You SHOULD NOT CHANGE basic_check, default_check functions!
- static void
- default_check(void) {
- int count = 0, total = 0;
- list_entry_t *le = &free_list;
- while ((le = list_next(le)) != &free_list) {
- struct Page *p = le2page(le, page_link);
- assert(PageProperty(p));
- count ++, total += p->property;
- }
- assert(total == nr_free_pages());
-
- basic_check();
-
- struct Page *p0 = alloc_pages(5), *p1, *p2;
- assert(p0 != NULL);
- assert(!PageProperty(p0));
-
- list_entry_t free_list_store = free_list;
- list_init(&free_list);
- assert(list_empty(&free_list));
- assert(alloc_page() == NULL);
-
- unsigned int nr_free_store = nr_free;
- nr_free = 0;
-
- free_pages(p0 + 2, 3);
- assert(alloc_pages(4) == NULL);
- assert(PageProperty(p0 + 2) && p0[2].property == 3);
- assert((p1 = alloc_pages(3)) != NULL);
- assert(alloc_page() == NULL);
- assert(p0 + 2 == p1);
-
- p2 = p0 + 1;
- free_page(p0);
- free_pages(p1, 3);
- assert(PageProperty(p0) && p0->property == 1);
- assert(PageProperty(p1) && p1->property == 3);
-
- assert((p0 = alloc_page()) == p2 - 1);
- free_page(p0);
- assert((p0 = alloc_pages(2)) == p2 + 1);
-
- free_pages(p0, 2);
- free_page(p2);
-
- assert((p0 = alloc_pages(5)) != NULL);
- assert(alloc_page() == NULL);
-
- assert(nr_free == 0);
- nr_free = nr_free_store;
-
- free_list = free_list_store;
- free_pages(p0, 5);
-
- le = &free_list;
- while ((le = list_next(le)) != &free_list) {
- struct Page *p = le2page(le, page_link);
- count --, total -= p->property;
- }
- assert(count == 0);
- assert(total == 0);
- }
-
- const struct pmm_manager default_pmm_manager = {
- .name = "default_pmm_manager",
- .init = default_init,
- .init_memmap = default_init_memmap,
- .alloc_pages = default_alloc_pages,
- .free_pages = default_free_pages,
- .nr_free_pages = default_nr_free_pages,
- .check = default_check,
- };
-
|