cu_Cbear 发表于 2012-01-05 20:16

linux启动内存分配器2。。。。。。

linux启动内存分配器2。。。。。。










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




view plaincopy to clipboard01./*分配size大小的空间*/
02.static void * __init alloc_bootmem_core(struct bootmem_data *bdata,
03.                  unsigned long size, unsigned long align,
04.                  unsigned long goal, unsigned long limit)
05.{
06.    unsigned long fallback = 0;
07.    unsigned long min, max, start, sidx, midx, step;
08.
09.    bdebug("nid=%td size=%lx [%lu pages] align=%lx goal=%lx limit=%lx\n",
10.      bdata - bootmem_node_data, size, PAGE_ALIGN(size) >> PAGE_SHIFT,
11.      align, goal, limit);
12.
13.    BUG_ON(!size);
14.    BUG_ON(align & (align - 1));
15.    BUG_ON(limit && goal + size > limit);
16.    /*如果没有映射位图返回空,分配失败*/
17.    if (!bdata->node_bootmem_map)
18.      return NULL;
19.
20.    min = bdata->node_min_pfn;
21.    max = bdata->node_low_pfn;
22.
23.    goal >>= PAGE_SHIFT;
24.    limit >>= PAGE_SHIFT;
25.
26.    if (limit && max > limit)
27.      max = limit;
28.    if (max <= min)
29.      return NULL;
30.    /*step为需要对齐于页面数*/
31.    step = max(align >> PAGE_SHIFT, 1UL);
32.    /*计算起始页面*/
33.    if (goal && min < goal && goal < max)
34.      start = ALIGN(goal, step);
35.    else
36.      start = ALIGN(min, step);
37.    /*计算分配页面区间*/
38.    sidx = start - bdata->node_min_pfn;
39.    midx = max - bdata->node_min_pfn;
40.    /*前一次分配的页号比这次开始分配的页面号大
41.    那么,如果第一次没有分配到,回退到这次的
42.    开始重新试,因为第一次分配是从上一次分配
43.    的位置开始的*/
44.    if (bdata->hint_idx > sidx) {      
45.         * Handle the valid case of sidx being zero and still
46.         * catch the fallback below.
47.         */
48.      fallback = sidx + 1;
49.      /*从上一次分配的位置开始,对齐与页面*/
50.      sidx = align_idx(bdata, bdata->hint_idx, step);
51.    }
52.
53.    while (1) {
54.      int merge;
55.      void *region;
56.      unsigned long eidx, i, start_off, end_off;
57.find_block:
58.      /*查找第一个为0的位*/
59.      sidx = find_next_zero_bit(bdata->node_bootmem_map, midx, sidx);
60.      sidx = align_idx(bdata, sidx, step);
61.      eidx = sidx + PFN_UP(size);/*结束位置*/
62.
63.      if (sidx >= midx || eidx > midx)/*找到结束了*/
64.            break;
65.
66.      for (i = sidx; i < eidx; i++)/*检查这段区域是否空闲*/
67.            if (test_bit(i, bdata->node_bootmem_map)) {/*如果不是,将跳过这段继续查找*/
68.                sidx = align_idx(bdata, i, step);
69.                if (sidx == i)
70.                  sidx += step;
71.                goto find_block;
72.            }
73.
74.      if (bdata->last_end_off & (PAGE_SIZE - 1) &&/*如果为相邻的页面,也就是说上次分配的页面和这次分配的开始页面为相邻的*/
75.                PFN_DOWN(bdata->last_end_off) + 1 == sidx)
76.            start_off = align_off(bdata, bdata->last_end_off, align);
77.      else
78.            start_off = PFN_PHYS(sidx);
79.
80.      /*merge==1表示上次结束和这次开始不在同一个页面上*/
81.      merge = PFN_DOWN(start_off) < sidx;
82.      end_off = start_off + size;
83.      /*更新数据*/
84.      bdata->last_end_off = end_off;
85.      bdata->hint_idx = PFN_UP(end_off);
86.
87.      /*
88.         * Reserve the area now:
89.         */
90.         /*设定新加入的页面为保留,就是将对应的映射位置1*/
91.      if (__reserve(bdata, PFN_DOWN(start_off) + merge,
92.                PFN_UP(end_off), BOOTMEM_EXCLUSIVE))
93.            BUG();
94.      /*对应开始地址的虚拟地址返回*/
95.      region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) +
96.                start_off);
97.      memset(region, 0, size);/*分配的大小*/
98.      /*
99.         * The min_count is set to 0 so that bootmem allocated blocks
100.         * are never reported as leaks.
101.         */
102.         /*调试用*/
103.      kmemleak_alloc(region, size, 0, 0);
104.      return region;
105.    }
106.
107.    if (fallback) {/*回退,重新查看*/
108.      sidx = align_idx(bdata, fallback - 1, step);
109.      fallback = 0;
110.      goto find_block;
111.    }
112.
113.    return NULL;
114.}

健康木乃伊 发表于 2012-01-05 20:25

谢谢分享
页: [1]
查看完整版本: linux启动内存分配器2。。。。。。