寻找小伙伴--linux kernel buddy system

你不是一个人

内核中的buddy system可谓是久仰大名,如雷贯耳。这年头找对象不容易,看看人内核里面是怎么找的,咱也好好学学,取取经~

敬个礼,握握手,你是我的好朋友

好了,说正经的,人是怎么找的呢?


__free_one_page()
...
    while (order < max_order - 1) {
        buddy_idx = __find_buddy_index(page_idx, order);
        buddy = page + (buddy_idx - page_idx);
        if (!page_is_buddy(page, buddy, order))
            goto done_merging;
        /*
         * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,
         * merge with it and move up one order.
         */
        if (page_is_guard(buddy)) {
            clear_page_guard(zone, buddy, order, migratetype);
        } else {
            list_del(&buddy->lru);
            zone->free_area[order].nr_free--;
            rmv_page_order(buddy);
        }
        combined_idx = buddy_idx & page_idx;
        page = page + (combined_idx - page_idx);
        page_idx = combined_idx;
        order++;
    }
...

其中重要的就是__find_buddy_index()。

/*
 * Locate the struct page for both the matching buddy in our
 * pair (buddy1) and the combined O(n+1) page they form (page).
 *
 * 1) Any buddy B1 will have an order O twin B2 which satisfies
 * the following equation:
 *     B2 = B1 ^ (1 << O)
 * For example, if the starting buddy (buddy2) is #8 its order
 * 1 buddy is #10:
 *     B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10
 *
 * 2) Any buddy B will have an order O+1 parent P which
 * satisfies the following equation:
 *     P = B & ~(1 << O)
 *
 * Assumption: *_mem_map is contiguous at least up to MAX_ORDER
 */
static inline unsigned long
__find_buddy_index(unsigned long page_idx, unsigned int order)
{
    return page_idx ^ (1 << order);
}

人注释写得真好,还有个例子给你看。我这个人有个毛病,一旦看懂了代码就老兴奋了。忍不住多说两句,估计人真正的大牛对这种代码了如指掌,根本没兴趣了。

我个人看完这个代码有两点体会:
* 使用某个位置上的数做异或就像是一个开关,原来有的就清,没的就置位
* 两个小伙伴的上一级伙伴,是这个位为零的那个

举个栗子

 +--------+--------+--------+--------+
 |8       |9       |10      |11      |
 +--------+--------+--------+--------+

 [======  2  =====] [=====  2  ======]

 [###############  4  ###############] 

举个栗子, 从上面这个图看出,O为1的时候,(8,9)为一组,(10,11)为一组。


8 ^ 2 = 0b 1000 ^ 0b 0010 = 0b 1010 = 10
10 ^ 2 = 0b 1010 ^ 0b 0010 = 0b 1000 = 8

可以看到,异或的结果就是order 2的那一位去反。很有意思。恩,是不是可以理解为男生找女生,女生找男生呢? (如果你硬要找一样的,我就没办法了)

那我们再来看如何找上一级的伙伴。从图上直观来看, (8,9) (9,10)的上一级就是数量为4的组。那他的首页面index就是8。

好了看看代码实现的效果

8 & ~2 = 0b 1000 & 0b 1101 = 0b 1000 = 8
10 & ~2 = 0b 1010 & 0b 1101 = 0b 1000 = 8

直观的效果就是大家都将order 2的那一位清除。哇哦,so easy.

大家注意一下实际代码中的一句

        combined_idx = buddy_idx & page_idx;
        page_idx = combined_idx;

在循环中,page_idx将作为下一次循环要去寻找伙伴的索引。那你想到了啥?
对了,正是因为自己的上一级伙伴是把order 2的那一位清空,所以自己和自己小伙伴做与运算就得到了上一级~

好了,我想你知道内核页分配中伙伴是怎么找的了~

到这里,就到这里,休息休息~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值