《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
9.8 KiB

12 years ago
12 years ago
  1. #include <pmm.h>
  2. #include <list.h>
  3. #include <string.h>
  4. #include <default_pmm.h>
  5. /* In the first fit algorithm, the allocator keeps a list of free blocks (known as the free list) and,
  6. on receiving a request for memory, scans along the list for the first block that is large enough to
  7. satisfy the request. If the chosen block is significantly larger than that requested, then it is
  8. usually split, and the remainder added to the list as another free block.
  9. Please see Page 196~198, Section 8.2 of Yan Wei Min's chinese book "Data Structure -- C programming language"
  10. */
  11. // LAB2 EXERCISE 1: YOUR CODE
  12. // you should rewrite functions: default_init,default_init_memmap,default_alloc_pages, default_free_pages.
  13. /*
  14. * Details of FFMA
  15. * (1) Prepare: In order to implement the First-Fit Mem Alloc (FFMA), we should manage the free mem block use some list.
  16. * The struct free_area_t is used for the management of free mem blocks. At first you should
  17. * be familiar to the struct list in list.h. struct list is a simple doubly linked list implementation.
  18. * You should know howto USE: list_init, list_add(list_add_after), list_add_before, list_del, list_next, list_prev
  19. * Another tricky method is to transform a general list struct to a special struct (such as struct page):
  20. * you can find some MACRO: le2page (in memlayout.h), (in future labs: le2vma (in vmm.h), le2proc (in proc.h),etc.)
  21. * (2) default_init: you can reuse the demo default_init fun to init the free_list and set nr_free to 0.
  22. * free_list is used to record the free mem blocks. nr_free is the total number for free mem blocks.
  23. * (3) default_init_memmap: CALL GRAPH: kern_init --> pmm_init-->page_init-->init_memmap--> pmm_manager->init_memmap
  24. * This fun is used to init a free block (with parameter: addr_base, page_number).
  25. * First you should init each page (in memlayout.h) in this free block, include:
  26. * p->flags should be set bit PG_property (means this page is valid. In pmm_init fun (in pmm.c),
  27. * the bit PG_reserved is setted in p->flags)
  28. * if this page is free and is not the first page of free block, p->property should be set to 0.
  29. * if this page is free and is the first page of free block, p->property should be set to total num of block.
  30. * p->ref should be 0, because now p is free and no reference.
  31. * We can use p->page_link to link this page to free_list, (such as: list_add_before(&free_list, &(p->page_link)); )
  32. * Finally, we should sum the number of free mem block: nr_free+=n
  33. * (4) default_alloc_pages: search find a first free block (block size >=n) in free list and reszie the free block, return the addr
  34. * of malloced block.
  35. * (4.1) So you should search freelist like this:
  36. * list_entry_t le = &free_list;
  37. * while((le=list_next(le)) != &free_list) {
  38. * ....
  39. * (4.1.1) In while loop, get the struct page and check the p->property (record the num of free block) >=n?
  40. * struct Page *p = le2page(le, page_link);
  41. * if(p->property >= n){ ...
  42. * (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.
  43. * Some flag bits of this page should be setted: PG_reserved =1, PG_property =0
  44. * unlink the pages from free_list
  45. * (4.1.2.1) If (p->property >n), we should re-caluclate number of the the rest of this free block,
  46. * (such as: le2page(le,page_link))->property = p->property - n;)
  47. * (4.1.3) re-caluclate nr_free (number of the the rest of all free block)
  48. * (4.1.4) return p
  49. * (4.2) If we can not find a free block (block size >=n), then return NULL
  50. * (5) default_free_pages: relink the pages into free list, maybe merge small free blocks into big free blocks.
  51. * (5.1) according the base addr of withdrawed blocks, search free list, find the correct position
  52. * (from low to high addr), and insert the pages. (may use list_next, le2page, list_add_before)
  53. * (5.2) reset the fields of pages, such as p->ref, p->flags (PageProperty)
  54. * (5.3) try to merge low addr or high addr blocks. Notice: should change some pages's p->property correctly.
  55. */
  56. free_area_t free_area;
  57. #define free_list (free_area.free_list)
  58. #define nr_free (free_area.nr_free)
  59. static void
  60. default_init(void) {
  61. list_init(&free_list);
  62. nr_free = 0;
  63. }
  64. static void
  65. default_init_memmap(struct Page *base, size_t n) {
  66. assert(n > 0);
  67. struct Page *p = base;
  68. for (; p != base + n; p ++) {
  69. assert(PageReserved(p));
  70. p->flags = p->property = 0;
  71. set_page_ref(p, 0);
  72. }
  73. base->property = n;
  74. SetPageProperty(base);
  75. nr_free += n;
  76. list_add(&free_list, &(base->page_link));
  77. }
  78. static struct Page *
  79. default_alloc_pages(size_t n) {
  80. assert(n > 0);
  81. if (n > nr_free) {
  82. return NULL;
  83. }
  84. struct Page *page = NULL;
  85. list_entry_t *le = &free_list;
  86. while ((le = list_next(le)) != &free_list) {
  87. struct Page *p = le2page(le, page_link);
  88. if (p->property >= n) {
  89. page = p;
  90. break;
  91. }
  92. }
  93. if (page != NULL) {
  94. list_del(&(page->page_link));
  95. if (page->property > n) {
  96. struct Page *p = page + n;
  97. p->property = page->property - n;
  98. list_add(&free_list, &(p->page_link));
  99. }
  100. nr_free -= n;
  101. ClearPageProperty(page);
  102. }
  103. return page;
  104. }
  105. static void
  106. default_free_pages(struct Page *base, size_t n) {
  107. assert(n > 0);
  108. struct Page *p = base;
  109. for (; p != base + n; p ++) {
  110. assert(!PageReserved(p) && !PageProperty(p));
  111. p->flags = 0;
  112. set_page_ref(p, 0);
  113. }
  114. base->property = n;
  115. SetPageProperty(base);
  116. list_entry_t *le = list_next(&free_list);
  117. while (le != &free_list) {
  118. p = le2page(le, page_link);
  119. le = list_next(le);
  120. if (base + base->property == p) {
  121. base->property += p->property;
  122. ClearPageProperty(p);
  123. list_del(&(p->page_link));
  124. }
  125. else if (p + p->property == base) {
  126. p->property += base->property;
  127. ClearPageProperty(base);
  128. base = p;
  129. list_del(&(p->page_link));
  130. }
  131. }
  132. nr_free += n;
  133. list_add(&free_list, &(base->page_link));
  134. }
  135. static size_t
  136. default_nr_free_pages(void) {
  137. return nr_free;
  138. }
  139. static void
  140. basic_check(void) {
  141. struct Page *p0, *p1, *p2;
  142. p0 = p1 = p2 = NULL;
  143. assert((p0 = alloc_page()) != NULL);
  144. assert((p1 = alloc_page()) != NULL);
  145. assert((p2 = alloc_page()) != NULL);
  146. assert(p0 != p1 && p0 != p2 && p1 != p2);
  147. assert(page_ref(p0) == 0 && page_ref(p1) == 0 && page_ref(p2) == 0);
  148. assert(page2pa(p0) < npage * PGSIZE);
  149. assert(page2pa(p1) < npage * PGSIZE);
  150. assert(page2pa(p2) < npage * PGSIZE);
  151. list_entry_t free_list_store = free_list;
  152. list_init(&free_list);
  153. assert(list_empty(&free_list));
  154. unsigned int nr_free_store = nr_free;
  155. nr_free = 0;
  156. assert(alloc_page() == NULL);
  157. free_page(p0);
  158. free_page(p1);
  159. free_page(p2);
  160. assert(nr_free == 3);
  161. assert((p0 = alloc_page()) != NULL);
  162. assert((p1 = alloc_page()) != NULL);
  163. assert((p2 = alloc_page()) != NULL);
  164. assert(alloc_page() == NULL);
  165. free_page(p0);
  166. assert(!list_empty(&free_list));
  167. struct Page *p;
  168. assert((p = alloc_page()) == p0);
  169. assert(alloc_page() == NULL);
  170. assert(nr_free == 0);
  171. free_list = free_list_store;
  172. nr_free = nr_free_store;
  173. free_page(p);
  174. free_page(p1);
  175. free_page(p2);
  176. }
  177. // LAB2: below code is used to check the first fit allocation algorithm (your EXERCISE 1)
  178. // NOTICE: You SHOULD NOT CHANGE basic_check, default_check functions!
  179. static void
  180. default_check(void) {
  181. int count = 0, total = 0;
  182. list_entry_t *le = &free_list;
  183. while ((le = list_next(le)) != &free_list) {
  184. struct Page *p = le2page(le, page_link);
  185. assert(PageProperty(p));
  186. count ++, total += p->property;
  187. }
  188. assert(total == nr_free_pages());
  189. basic_check();
  190. struct Page *p0 = alloc_pages(5), *p1, *p2;
  191. assert(p0 != NULL);
  192. assert(!PageProperty(p0));
  193. list_entry_t free_list_store = free_list;
  194. list_init(&free_list);
  195. assert(list_empty(&free_list));
  196. assert(alloc_page() == NULL);
  197. unsigned int nr_free_store = nr_free;
  198. nr_free = 0;
  199. free_pages(p0 + 2, 3);
  200. assert(alloc_pages(4) == NULL);
  201. assert(PageProperty(p0 + 2) && p0[2].property == 3);
  202. assert((p1 = alloc_pages(3)) != NULL);
  203. assert(alloc_page() == NULL);
  204. assert(p0 + 2 == p1);
  205. p2 = p0 + 1;
  206. free_page(p0);
  207. free_pages(p1, 3);
  208. assert(PageProperty(p0) && p0->property == 1);
  209. assert(PageProperty(p1) && p1->property == 3);
  210. assert((p0 = alloc_page()) == p2 - 1);
  211. free_page(p0);
  212. assert((p0 = alloc_pages(2)) == p2 + 1);
  213. free_pages(p0, 2);
  214. free_page(p2);
  215. assert((p0 = alloc_pages(5)) != NULL);
  216. assert(alloc_page() == NULL);
  217. assert(nr_free == 0);
  218. nr_free = nr_free_store;
  219. free_list = free_list_store;
  220. free_pages(p0, 5);
  221. le = &free_list;
  222. while ((le = list_next(le)) != &free_list) {
  223. struct Page *p = le2page(le, page_link);
  224. count --, total -= p->property;
  225. }
  226. assert(count == 0);
  227. assert(total == 0);
  228. }
  229. const struct pmm_manager default_pmm_manager = {
  230. .name = "default_pmm_manager",
  231. .init = default_init,
  232. .init_memmap = default_init_memmap,
  233. .alloc_pages = default_alloc_pages,
  234. .free_pages = default_free_pages,
  235. .nr_free_pages = default_nr_free_pages,
  236. .check = default_check,
  237. };