Linux kernel rb-tree (1)

本文主要目的是對 Linux kernel 中 rb-tree 有個(gè)初步印象,方便理解后面的文章

RB-TREE

// linux-5.4/lib/rb-tree.c
 * red-black trees properties:  http://en.wikipedia.org/wiki/Rbtree
 *
 *  1) A node is either red or black
 *  2) The root is black
 *  3) All leaves (NULL) are black
 *  4) Both children of every red node are black
 *  5) Every simple path from root to leaves contains the same number
 *     of black nodes.
 *
 *  4 and 5 give the O(log n) guarantee, since 4 implies you cannot have two
 *  consecutive red nodes in a path and every red node is therefore followed by
 *  a black. So if B is the number of black nodes on every simple path (as per
 *  5), then the longest possible path due to 4 is 2B.

建議熟讀并背誦

consecutive
CET6 TEM4
英 [k?n?sekj?t?v] 美 [k?n?sekj?t?v]
*   adj. 連貫的;連續(xù)不斷的

Data structures & Macros

// include/linux/rbtree_augmented.h
#define RB_RED          0
#define RB_BLACK        1

// linux-5.4/include/linux/rbtree.h

struct rb_root {
        struct rb_node *rb_node;
};

struct rb_node {
        unsigned long  __rb_parent_color;
        struct rb_node *rb_right;
        struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));

#define RB_ROOT (struct rb_root) { NULL, }
#define rb_entry(ptr, type, member) container_of(ptr, type, member)

建議手敲個(gè)十幾遍,先記熟。

APIs

// include/linux/rbtree.h

static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
                                struct rb_node ** rb_link)

extern void rb_insert_color(struct rb_node *, struct rb_root *);

extern void rb_erase(struct rb_node *, struct rb_root *);

Example

// include/linux/vmalloc.h
struct vmap_area {
        unsigned long va_start;
        unsigned long va_end;
        unsigned long flags;
        struct rb_node rb_node;         /* address sorted rbtree */
        // ...
};

struct vm_struct {
        struct vm_struct        *next;
        void                    *addr;
        unsigned long           size;
        unsigned long           flags;
        struct page             **pages;
        unsigned int            nr_pages;
        phys_addr_t             phys_addr;
        const void              *caller;
};


// mm/vmalloc.c
static struct rb_root vmap_area_root = RB_ROOT;

static struct vmap_area *__find_vmap_area(unsigned long addr);
static void __insert_vmap_area(struct vmap_area *va);
static void __free_vmap_area(struct vmap_area *va);

// 搜索
static struct vmap_area *__find_vmap_area(unsigned long addr)
{
                // 取 rb_root.rb_entry 地址
        struct rb_node *n = vmap_area_root.rb_node;

        // 遍歷 rb_tree
        while (n) {
                struct vmap_area *va;

                // 獲取 rb_node 的container
                va = rb_entry(n, struct vmap_area, rb_node);

                // 比較目標(biāo)值
                if (addr < va->va_start)
                        n = n->rb_left;
                else if (addr > va->va_start)
                        n = n->rb_right;
                else
                        return va;
        }

        return NULL;
}

// 插入
static void __insert_vmap_area(struct vmap_area *va)
{
        struct rb_node **p = &vmap_area_root.rb_node;
        struct rb_node *parent = NULL;
        struct rb_node *tmp;

        // 遍歷 rb_tree 
        while (*p) {
                struct vmap_area *tmp_va;

                parent = *p;
                tmp_va = rb_entry(parent, struct vmap_area, rb_node);

                // 比較,找到合適的插入位置 
                if (va->va_start < tmp_va->va_end)
                        p = &(*p)->rb_left;
                else if (va->va_end > tmp_va->va_start)
                        p = &(*p)->rb_right;
                else
                        BUG();
        }

        // 插入節(jié)點(diǎn)
        rb_link_node(&va->rb_node, parent, p);
        // 上色
        rb_insert_color(&va->rb_node, &vmap_area_root);

                //...
}



// 刪除
static void __free_vmap_area(struct vmap_area *va){
        // ...
        rb_erase(&va->rb_node, &vmap_area_root);
        // ...
}

// 創(chuàng)建節(jié)點(diǎn)
static struct vmap_area *alloc_vmap_area(unsigned long size,
                                unsigned long align,
                                unsigned long vstart, unsigned long vend,
                                int node, gfp_t gfp_mask)
{
        struct vmap_area *va;
// ...

        va = kmalloc_node(sizeof(struct vmap_area),
                        gfp_mask & GFP_RECLAIM_MASK, node);
// ...
        va->va_start = addr;
        va->va_end = addr + size;
        va->flags = 0;
        __insert_vmap_area(va);
// ...
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • application [??pl?'ke??(?)n]應(yīng)用程式應(yīng)用、應(yīng)用程序 application frame...
    我不白先生閱讀 2,521評論 0 3
  • 久違的晴天,家長會。 家長大會開好到教室時(shí),離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,866評論 16 22
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會,身份的轉(zhuǎn)變要...
    余生動聽閱讀 10,912評論 0 11
  • 可愛進(jìn)取,孤獨(dú)成精。努力飛翔,天堂翱翔。戰(zhàn)爭美好,孤獨(dú)進(jìn)取。膽大飛翔,成就輝煌。努力進(jìn)取,遙望,和諧家園??蓯塾巫?..
    趙原野閱讀 3,541評論 1 1
  • 在妖界我有個(gè)名頭叫胡百曉,無論是何事,只要找到胡百曉即可有解決的辦法。因?yàn)槭侵缓偞蠹乙杂瀭饔灲形摇皟A城百曉”,...
    貓九0110閱讀 3,728評論 7 3

友情鏈接更多精彩內(nèi)容