免费注册 查看新帖 |

Chinaunix

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

linux启动内存分配器 3。。。。。。。。。。 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-01-05 16:28 |只看该作者 |倒序浏览
linux启动内存分配器 3。。。。。。。。。。
  1. view plaincopy to clipboardprint?/**
  2. * reserve_bootmem - mark a page range as usable
  3. * @addr: starting address of the range
  4. * @size: size of the range in bytes
  5. * @flags: reservation flags (see linux/bootmem.h)
  6. *
  7. * Partial pages will be reserved.
  8. *
  9. * The range must be contiguous but may span node boundaries.
  10. */  
  11. int __init reserve_bootmem(unsigned long addr, unsigned long size,  
  12.                 int flags)  
  13. {  
  14.     unsigned long start, end;  
  15.   
  16.     start = PFN_DOWN(addr);/*下界*/  
  17.     end = PFN_UP(addr + size);/*上界*/  
  18.   
  19.     return mark_bootmem(start, end, 1, flags);  
  20. }  
  21. /**
  22. * reserve_bootmem - mark a page range as usable
  23. * @addr: starting address of the range
  24. * @size: size of the range in bytes
  25. * @flags: reservation flags (see linux/bootmem.h)
  26. *
  27. * Partial pages will be reserved.
  28. *
  29. * The range must be contiguous but may span node boundaries.
  30. */
  31. int __init reserve_bootmem(unsigned long addr, unsigned long size,
  32.                             int flags)
  33. {
  34.         unsigned long start, end;

  35.         start = PFN_DOWN(addr);/*下界*/
  36.         end = PFN_UP(addr + size);/*上界*/

  37.         return mark_bootmem(start, end, 1, flags);
  38. }view plaincopy to clipboardprint?/*保留指定内存区间*/  
  39. static int __init mark_bootmem(unsigned long start, unsigned long end,  
  40.                 int reserve, int flags)  
  41. {  
  42.     unsigned long pos;  
  43.     bootmem_data_t *bdata;  
  44.   
  45.     pos = start;  
  46.     /*通过bdata_list链表找到在指定区间的bdata*/  
  47.     list_for_each_entry(bdata, &bdata_list, list) {  
  48.         int err;  
  49.         unsigned long max;  
  50.   
  51.         if (pos < bdata->node_min_pfn ||  
  52.             pos >= bdata->node_low_pfn) {  
  53.             BUG_ON(pos != start);  
  54.             continue;  
  55.         }  
  56.   
  57.         max = min(bdata->node_low_pfn, end);  
  58.         /*设置为保留*/  
  59.         err = mark_bootmem_node(bdata, pos, max, reserve, flags);  
  60.         if (reserve && err) {/*如果出错,递归调用*/  
  61.             mark_bootmem(start, pos, 0, 0);  
  62.             return err;  
  63.         }  
  64.   
  65.         if (max == end)  
  66.             return 0;  
  67.         pos = bdata->node_low_pfn;  
  68.     }  
  69.     BUG();  
  70. }  
  71. /*保留指定内存区间*/
  72. static int __init mark_bootmem(unsigned long start, unsigned long end,
  73.                                 int reserve, int flags)
  74. {
  75.         unsigned long pos;
  76.         bootmem_data_t *bdata;

  77.         pos = start;
  78.         /*通过bdata_list链表找到在指定区间的bdata*/
  79.         list_for_each_entry(bdata, &bdata_list, list) {
  80.                 int err;
  81.                 unsigned long max;

  82.                 if (pos < bdata->node_min_pfn ||
  83.                     pos >= bdata->node_low_pfn) {
  84.                         BUG_ON(pos != start);
  85.                         continue;
  86.                 }

  87.                 max = min(bdata->node_low_pfn, end);
  88.                 /*设置为保留*/
  89.                 err = mark_bootmem_node(bdata, pos, max, reserve, flags);
  90.                 if (reserve && err) {/*如果出错,递归调用*/
  91.                         mark_bootmem(start, pos, 0, 0);
  92.                         return err;
  93.                 }

  94.                 if (max == end)
  95.                         return 0;
  96.                 pos = bdata->node_low_pfn;
  97.         }
  98.         BUG();
  99. }
复制代码
三、内存的分配和释放

介绍了上面的初始化流程,对于分配和释放就简单了,分配就是将分配器映射位图中对应的位置1,释放过程相反。


[code]view plaincopy to clipboardprint?/*分配size大小的空间*/  
static void * __init alloc_bootmem_core(struct bootmem_data *bdata,  
                    unsigned long size, unsigned long align,  
                    unsigned long goal, unsigned long limit)  
{  
    unsigned long fallback = 0;  
    unsigned long min, max, start, sidx, midx, step;  
  
    bdebug("nid=%td size=%lx [%lu pages] align=%lx goal=%lx limit=%lx\n",  
        bdata - bootmem_node_data, size, PAGE_ALIGN(size) >> PAGE_SHIFT,  
        align, goal, limit);  
  
    BUG_ON(!size);  
    BUG_ON(align & (align - 1));  
    BUG_ON(limit && goal + size > limit);  
    /*如果没有映射位图返回空,分配失败*/  
    if (!bdata->node_bootmem_map)  
        return NULL;  
  
    min = bdata->node_min_pfn;  
    max = bdata->node_low_pfn;  
  
    goal >>= PAGE_SHIFT;  
    limit >>= PAGE_SHIFT;  
  
    if (limit && max > limit)  
        max = limit;  
    if (max <= min)  
        return NULL;  
    /*step为需要对齐于页面数*/  
    step = max(align >> PAGE_SHIFT, 1UL);  
    /*计算起始页面*/  
    if (goal && min < goal && goal < max)  
        start = ALIGN(goal, step);  
    else  
        start = ALIGN(min, step);  
    /*计算分配页面区间*/  
    sidx = start - bdata->node_min_pfn;  
    midx = max - bdata->node_min_pfn;  
    /*前一次分配的页号比这次开始分配的页面号大
    那么,如果第一次没有分配到,回退到这次的
    开始重新试,因为第一次分配是从上一次分配
    的位置开始的*/  
    if (bdata->hint_idx > sidx) {      
         * Handle the valid case of sidx being zero and still  
         * catch the fallback below.  
         */  
        fallback = sidx + 1;  
        /*从上一次分配的位置开始,对齐与页面*/  
        sidx = align_idx(bdata, bdata->hint_idx, step);  
    }  
  
    while (1) {  
        int merge;  
        void *region;  
        unsigned long eidx, i, start_off, end_off;  
find_block:  
        /*查找第一个为0的位*/  
        sidx = find_next_zero_bit(bdata->node_bootmem_map, midx, sidx);  
        sidx = align_idx(bdata, sidx, step);  
        eidx = sidx + PFN_UP(size);/*结束位置*/  
  
        if (sidx >= midx || eidx > midx)/*找到结束了*/  
            break;  
  
        for (i = sidx; i < eidx; i++)/*检查这段区域是否空闲*/  
            if (test_bit(i, bdata->node_bootmem_map)) {/*如果不是,将跳过这段继续查找*/  
                sidx = align_idx(bdata, i, step);  
                if (sidx == i)  
                    sidx += step;  
                goto find_block;  
            }  
  
        if (bdata->last_end_off & (PAGE_SIZE - 1) &&/*如果为相邻的页面,也就是说上次分配的页面和这次分配的开始页面为相邻的*/  
                PFN_DOWN(bdata->last_end_off) + 1 == sidx)  
            start_off = align_off(bdata, bdata->last_end_off, align);  
        else  
            start_off = PFN_PHYS(sidx);  
  
        /*merge==1表示上次结束和这次开始不在同一个页面上*/  
        merge = PFN_DOWN(start_off) < sidx;  
        end_off = start_off + size;  
        /*更新数据*/  
        bdata->last_end_off = end_off;  
        bdata->hint_idx = PFN_UP(end_off);  
  
        /*
         * Reserve the area now:
         */  
         /*设定新加入的页面为保留,就是将对应的映射位置1*/  
        if (__reserve(bdata, PFN_DOWN(start_off) + merge,  
                PFN_UP(end_off), BOOTMEM_EXCLUSIVE))  
            BUG();  
        /*对应开始地址的虚拟地址返回*/  
        region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) +  
                start_off);  
        memset(region, 0, size);/*分配的大小*/  
        /*
         * The min_count is set to 0 so that bootmem allocated blocks
         * are never reported as leaks.
         */  
         /*调试用*/  
        kmemleak_alloc(region, size, 0, 0);  
        return region;  
    }  
  
    if (fallback) {/*回退,重新查看*/  
        sidx = align_idx(bdata, fallback - 1, step);  
        fallback = 0;  
        goto find_block;  
    }  
  
    return NULL;  
}  [/code

论坛徽章:
0
2 [报告]
发表于 2012-01-05 16:29 |只看该作者
谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP