免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2055 | 回复: 0
打印 上一主题 下一主题

仿照linux中使用的内存管理机制改写的程序,请高手指点 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-10-16 18:30 |只看该作者 |倒序浏览
为了给自己DIY的操作系统完善内存管理模块,课余时间仿照linux系统中常用的buddy页内存分配基址,按照自己的理解简化后写了一个小程序,请大家帮看看逻辑上有没有问题,我尽量注释清楚本人的思路,谢谢。
  1. #include <page.h>
  2. static struct list_node page_list[MAX_ORDER];
  3. /**内部函数,获取满足需求内存页数的最小order
  4. * @param cnt:申请的页面大小
  5. * @return :满足要求的最小order
  6. */
  7. static unsigned int cnt_to_min_order(unsigned int cnt){
  8. if (cnt <=          1) return 0;
  9. if (cnt <=          2) return 1;
  10. if (cnt <=          4) return 2;
  11. if (cnt <=          8) return 3;
  12. if (cnt <=         16) return 4;
  13. if (cnt <=         32) return 5;
  14. if (cnt <=         64) return 6;
  15. if (cnt <=        128) return 7;
  16. if (cnt <=        256) return 8;
  17. if (cnt <=        512) return 9;
  18. if (cnt <=   1 * 1024) return 10;
  19. if (cnt <=   2 * 1024) return 11;       
  20. }
  21. /**内部函数,获取最接近(小于)释放page数量的order
  22. * @param cnt:释放的页数量
  23. * @return :满足要求的最大order
  24. */
  25. static unsigned int cnt_to_max_order(unsigned int cnt){

  26. if(cnt  >=        1024)return 10;
  27. if(cnt  >=        512 )return 9;
  28. if(cnt  >=        256 )return 8;
  29. if(cnt  >=        128 )return 7;
  30. if(cnt  >=        64  )return 6;
  31. if(cnt  >=        32  )return 5;
  32. if(cnt  >=        16  )return 4;
  33. if(cnt  >=        8   )return 3;
  34. if(cnt  >=        4   )return 2;
  35. if(cnt  >=        2   )return 1;
  36. return 0;
  37. }

  38. /**内部函数,获取指定order值的内存页
  39. * @param _order
  40. */
  41. static struct page *_get_pages(unsigned int _order){
  42. struct page *page;
  43. unsigned int order = _order;
  44. struct list_node *page_nod;
  45. for(;order<=MAX_ORDER;order++){ //查找该order链表是否空闲
  46. page_nod = &page_list[order]
  47. if(!list_is_empty(page_nod))//不空闲则在该order上分配,否则到更高一级的border上找
  48.     break;
  49. }

  50. if(oder<=MAX_ORDER){
  51. list_del_node(&page_nod->next);
  52. page = list_entry(&page_nod->next,struct page,list);
  53. //下面的程序将多余的页面分配到各自的order中,例如需要4页内存,但是找到1块包含32个页面的块,则分成16,8,4
  54. //个页面分别挂在各自的order上,并返回剩下的4个页面
  55. while(order>_order){
  56.     free_pages(page+(1<<(order-1)),order-1);
  57.     order--;
  58. }
  59. return page;
  60. }
  61. return NULL;
  62. }
  63. /**查询伙伴是否空闲
  64. * @param order:需要查询的内存块(在指定的内存块查询)
  65. * @param page_idx:指定页码
  66. * return 0:非空闲,1:空闲
  67. */
  68. static bool_t is_buddy_empty(unsigned int order,unsigned int page_idx){
  69. struct list_nod *iter;
  70. struct page *page = pfn_to_page(page_idx);
  71. list_for_each(iter,&page_list[order]){
  72.             if(((unsigned int)list_entry(iter,struct page,list)) == (unsigned int)page)
  73.                     return 1;
  74.         }
  75. return 0;
  76. }
  77. /**函数,释放一页内存
  78. * @param page 页指针
  79. */
  80. void free_one_page(struct page *page){
  81. free_pages(page,0);
  82. }
  83. /**释放多个页面
  84. * @param page 第一页指针
  85. * @param order order值
  86. * return 0:失败 1:成功
  87. */
  88. bool_t free_pages(struct page *page,unsigned int order){
  89. unsigned int buddy_idx;
  90. struct list_nod *iter;
  91. unsigned int page_idx=page_to_pfn(page); //通过页指针返回该页对应的页表pfn
  92. if(page_idx%(1<<order)==0){ //参数检查,释放的page的第一页标必须是该order值的整数倍,否则出错
  93.                 while(order<MAX_ORDER-1){
  94.                         buddy_idx = page_idx^(1<<order);     //找到其伙伴对应的页标
  95.                         if(is_buddy_empty(order,buddy_idx)){  //*查看伙伴是否空闲*//
  96.                          //如果找到伙伴并且是空闲的,则合并到上级链表上
  97.                          list_del_node(&pfn_to_page(buddy_idx)->list); //先在该链表上删除伙伴
  98.                          page_idx=page_idx<buddy_idx?page_idx:buddy_idx; //合并
  99.                          order++;    //上级buddy
  100.                         }
  101.                         else break;
  102.                 }
  103.                 //伙伴非空闲或者其他已经到了最高级buddy,挂在本order链表上,插入顺序按照页标pfn从小到大
  104.                 list_for_each(iter,&page_list[order]){
  105.                        if((unsigned int)list_entry(iter,struct page,list)) > (unsigned int)page){
  106.                              break;
  107.                        }
  108.                 }
  109.                 list_add_head(&page->list,iter); //挂接在该buddy上
  110.                 return 1;
  111. }
  112. return 0;
  113. }
  114. /**申请多个页面
  115. * @param cnt 需要申请的页面数
  116. * return 页面指针
  117. */
  118. void *get_pages(unsigned int cnt){
  119. struct page *page,*_page;
  120. unsigned int _page_cnt;
  121. unsigned int order,order1;
  122. order = cnt_to_min_order(cnt);//找到符合要求的最小order值
  123. page = _get_pages(order);    //分配页内存
  124. _page_cnt = (1<<order)-cnt;  //计算剩余的页
  125. _page = page +(1<<order);    //指向分配的页块末尾
  126. while(_page_cnt !=0)        //将多余的页返回给内存管理模块 比如需要分配33块页内存,经过order计算分配了64块
  127.                                 //剩余31块则分为16 8 4 2 1块分别返回给各自的order
  128.     {
  129.             order1 = cnt_to_max_order(_page_cnt);
  130.             free_pages(_page -(1<<1oredr1) ,oredr1);
  131.             _page_cnt -= (1 << oredr1);
  132.     }
  133. return (void *)page;
  134. }
  135. /**内存初始化函数
  136. * @param bss_end:链接脚本传过来的bss段末地址
  137. */
  138. void men_init(unsigned int bss_end){
  139. unsigned int cnt,used_page;
  140. page_start = (struct page *page)align_up(bss_end);//page结构放在bss_end的下一个页面开始的地方
  141. used_page = (unsigned int)(align_up(bss_end)+align_up(sizeof(struct page)*max_mapnr))/PAGE_SIZE;//已经使用的page数量,包含内核以及page结构本身的空间,并对齐到页边界
  142. memset((void *)page_start,0,align_up(sizeof(struct page)*max_mapnr));//将page结构占用空间清零,max_mapnr为整个内存需要的page数
  143. for(cnt=0;cnt < used_page;cnt++){  //将内核以及page结构本身所占用的内存填充进对应的page结构,防止被下面的释放程序给释放
  144. (page_start+cnt)->_count=0xff;//页面引用计数
  145. }
  146. for(;cnt < max_mapnr;cnt++){  //释放空闲内存,同时初始化buddy结构
  147.     if((page_start+cnt)->_count==0)//该页面未被使用
  148. free_one_page(page_start+cnt);
  149. }
  150. }
复制代码
如果这一步没什么问题下一步将改造slub分配器,适合更小内存分配策略。纯粹是DIY性质。所以各位看客如果有质疑写这个程序有什么用处的请绕道。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP