美文网首页
Linux kernel 数据结构 hlist (2)

Linux kernel 数据结构 hlist (2)

作者: _invincible_ | 来源:发表于2021-01-30 12:07 被阅读0次

    本文内容:添加节点,删除节点相关API的用法,写了个Demo 打印一个hlist;

    • 前情提要
      上文 讲了hlist怎么创建,创建后长什么样

    • API

    /**
     * hash_add - add an object to a hashtable
     * @hashtable: hashtable to add to
     * @node: the &struct hlist_node of the object to be added
     * @key: the key of the object to be added
     */
    #define hash_add(hashtable, node, key)                                          \
            hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
    
    static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
    {
            struct hlist_node *first = h->first;
            n->next = first;
            if (first)
                    first->pprev = &n->next;
            WRITE_ONCE(h->first, n);
            n->pprev = &h->first;
    }
    
    /* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
    #define hash_min(val, bits)                                                     \
            (sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
    
    #define HASH_SIZE(name) (ARRAY_SIZE(name))
    #define HASH_BITS(name) ilog2(HASH_SIZE(name))
    
    // ilog2 - log base 2 of 32-bit or a 64-bit unsigned value
    // 计算log值
    
    
    /**
     * hash_del - remove an object from a hashtable
     * @node: &struct hlist_node of the object to remove
     */
    static inline void hash_del(struct hlist_node *node)
    {
            hlist_del_init(node);
    }
    
    static inline void hlist_del_init(struct hlist_node *n)
    {
            if (!hlist_unhashed(n)) {
                    __hlist_del(n);
                    INIT_HLIST_NODE(n);
            }
    }
    
    static inline void __hlist_del(struct hlist_node *n)
    {
            struct hlist_node *next = n->next;
            struct hlist_node **pprev = n->pprev;
    
            WRITE_ONCE(*pprev, next);
            if (next)
                    next->pprev = pprev;
    }
    
    • code
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/types.h>
    #include <linux/hashtable.h>
    #include <linux/vmalloc.h>
    
    #define HBITS 2
    
    DEFINE_HASHTABLE(planet_htable, HBITS);
    
    struct planet {
            int mass;
            char name[100];
            struct hlist_node node;
    };
    
    
    struct planet *create_planet(int mass, char *name);
    void destroy_planet(struct planet *p);
    void print_planet_mem(struct planet *p);
    void hlist_test(void);
    void hlist_print(void);
    
    struct planet *create_planet(int mass, char *name){
            struct planet *p;
            p = vmalloc(sizeof(struct planet));
            if(!p){
                    pr_err("[!] Create planet failed.\n");
                    return NULL;
            }
    
            memset(p, 0, sizeof(struct planet));
    
            p->mass = mass;
            strcpy(p->name, name);
    
            return p;
    }
    
    void destroy_planet(struct planet *p){
            hash_del(&p->node);
            vfree(p);
    }
    
    void print_planet_mem(struct planet *p){
            char *buff, *pos;
    
            buff = vmalloc(4096);
    
            if(!buff){
                    pr_err("[!] vmalloc failed!\n");
                    return;
            }
    
            memset(buff, 0, 4096);
    
            pos = buff;
    
            pos += sprintf(pos, "++++++ memory region for %s struct %px ++++++\n", p->name, p);
            pos += sprintf(pos, "<%px> %s->mass: %d\n", &p->mass, p->name, p->mass);
            pos += sprintf(pos, "<%px> %s->name: %px, %s\n", &p->name, p->name, p->name, p->name);
            pos += sprintf(pos, "<%px> %s->node: \n", &p->node, p->name);
            pos += sprintf(pos, "<%px> \t%s->node.next: %px\n", &p->node.next, p->name, p->node.next);
            pos += sprintf(pos, "<%px> \t%s->node.pprev: %px\n", &p->node.pprev, p->name, p->node.pprev);
            pos += sprintf(pos, "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
    
            pr_info("%s\n", buff);
    
            vfree(buff);
    
    }
    
    
    void hlist_test(void){
            struct planet *earth;
            struct planet *mars;
            struct planet *venus;
    
            earth = create_planet(0, "Earth");
            mars  = create_planet(1, "Mars ");
            venus = create_planet(1, "Venus");
    
            hash_add(planet_htable, &earth->node, earth->mass);
            hash_add(planet_htable, &mars->node, mars->mass);
            hash_add(planet_htable, &venus->node, venus->mass);
    
            print_planet_mem(earth);
            print_planet_mem(mars);
            print_planet_mem(venus);
    
            pr_info("++++++++++++++++ hlist initiated ++++++++++++++++++++++++++\n");
            hlist_print();
            pr_info("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
    
            destroy_planet(venus);
    
            pr_info("++++++++++++++++++++++ venus destroyed ++++++++++++++++++++\n");
            hlist_print();
            pr_info("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
    
            destroy_planet(earth);
            destroy_planet(mars);
    
    }
    
    void hlist_print(void){
            /* 这里我就直接打印的,正经的遍历方法后面再说 */
    
            char *buff, *pos;
            int i;
            struct hlist_node *next;
    
            buff = vmalloc(4096);
            memset(buff, 0, 4096);
    
            if(!buff){
                    pr_err("[!] vmalloc failed!\n");
                    return;
            }
    
            pos = buff;
    
            for(i = 0; i < 1<<HBITS; i++){
                    pos += sprintf(pos, "<%px> planet_htable[%d].first: %px\n", &planet_htable[i], i, planet_htable[i].first);
            }
    
            pos += sprintf(pos, "%s", "\n");
    
            for(i = 0; i < 1<<HBITS; i++){
                    if(!planet_htable[i].first)
                            continue;
    
                    pos += sprintf(pos, "<%px> planet_htable[%d].first->next: %px\n", &planet_htable[i].first->next, i, planet_htable[i].first->next);
                    pos += sprintf(pos, "<%px> planet_htable[%d].first->pprev: %px\n\n", &planet_htable[i].first->pprev, i, planet_htable[i].first->pprev);
    
                    next = planet_htable[i].first->next;
    
                    while(next){
                            pos += sprintf(pos, "<%px> next->next: %px\n", &next->next, next->next);
                            pos += sprintf(pos, "<%px> next->pprev: %px\n", &next->pprev, next->pprev);
                            next = next->next;
                    }
            }
    
            pr_info("%s\n", buff);
            vfree(buff);
    }
    
    static int __init hlist_t_init(void)
    {
        printk(KERN_INFO "Hello hlist_t\n");
    
        hlist_test();
    
        return 0;
    }
    
    static void __exit hlist_t_exit(void)
    {
        printk(KERN_INFO "Goodbye hlist_t\n");
    }
    
    
    module_init(hlist_t_init);
    module_exit(hlist_t_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("X++0");
    MODULE_DESCRIPTION("Kernel xxx Module.");
    MODULE_VERSION("0.1");
    
    • output
    [ 1781.367263] ++++++ memory region for Earth struct ffffc9000009f000 ++++++
    [ 1781.367263] <ffffc9000009f000> Earth->mass: 0
    [ 1781.367263] <ffffc9000009f004> Earth->name: ffffc9000009f004, Earth
    [ 1781.367263] <ffffc9000009f068> Earth->node:
    [ 1781.367263] <ffffc9000009f068>   Earth->node.next: 0000000000000000
    [ 1781.367263] <ffffc9000009f070>   Earth->node.pprev: ffffffffa0002340
    [ 1781.367263] +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    [ 1781.367263]
    [ 1781.367263]
    [ 1781.374884] ++++++ memory region for Mars  struct ffffc900000a1000 ++++++
    [ 1781.374884] <ffffc900000a1000> Mars ->mass: 1
    [ 1781.374884] <ffffc900000a1004> Mars ->name: ffffc900000a1004, Mars
    [ 1781.374884] <ffffc900000a1068> Mars ->node:
    [ 1781.374884] <ffffc900000a1068>   Mars ->node.next: 0000000000000000
    [ 1781.374884] <ffffc900000a1070>   Mars ->node.pprev: ffffc900000a3068
    [ 1781.374884] +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    [ 1781.374884]
    [ 1781.374884]
    [ 1781.382078] ++++++ memory region for Venus struct ffffc900000a3000 ++++++
    [ 1781.382078] <ffffc900000a3000> Venus->mass: 1
    [ 1781.382078] <ffffc900000a3004> Venus->name: ffffc900000a3004, Venus
    [ 1781.382078] <ffffc900000a3068> Venus->node:
    [ 1781.382078] <ffffc900000a3068>   Venus->node.next: ffffc900000a1068
    [ 1781.382078] <ffffc900000a3070>   Venus->node.pprev: ffffffffa0002348
    [ 1781.382078] +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    [ 1781.388669] ++++++++++++++++ hlist initiated ++++++++++++++++++++++++++
    [ 1781.389716] <ffffffffa0002340> planet_htable[0].first: ffffc9000009f068
    [ 1781.389716] <ffffffffa0002348> planet_htable[1].first: ffffc900000a3068
    [ 1781.389716] <ffffffffa0002350> planet_htable[2].first: 0000000000000000
    [ 1781.389716] <ffffffffa0002358> planet_htable[3].first: 0000000000000000
    [ 1781.389716]
    [ 1781.389716] <ffffc9000009f068> planet_htable[0].first->next: 0000000000000000
    [ 1781.389716] <ffffc9000009f070> planet_htable[0].first->pprev: ffffffffa0002340
    [ 1781.389716]
    [ 1781.389716] <ffffc900000a3068> planet_htable[1].first->next: ffffc900000a1068
    [ 1781.389716] <ffffc900000a3070> planet_htable[1].first->pprev: ffffffffa0002348
    [ 1781.389716]
    [ 1781.389716] <ffffc900000a1068> next->next: 0000000000000000
    [ 1781.389716] <ffffc900000a1070> next->pprev: ffffc900000a3068
    [ 1781.389716]
    [ 1781.399761] +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    [ 1781.399761]
    [ 1781.400872] ++++++++++++++++++++++ venus destroyed ++++++++++++++++++++
    [ 1781.401788] <ffffffffa0002340> planet_htable[0].first: ffffc9000009f068
    [ 1781.401788] <ffffffffa0002348> planet_htable[1].first: ffffc900000a1068
    [ 1781.401788] <ffffffffa0002350> planet_htable[2].first: 0000000000000000
    [ 1781.401788] <ffffffffa0002358> planet_htable[3].first: 0000000000000000
    [ 1781.401788]
    [ 1781.401788] <ffffc9000009f068> planet_htable[0].first->next: 0000000000000000
    [ 1781.401788] <ffffc9000009f070> planet_htable[0].first->pprev: ffffffffa0002340
    [ 1781.401788]
    [ 1781.401788] <ffffc900000a1068> planet_htable[1].first->next: 0000000000000000
    [ 1781.401788] <ffffc900000a1070> planet_htable[1].first->pprev: ffffffffa0002348
    [ 1781.401788]
    [ 1781.401788]
    [ 1781.409696] +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    ...
    
    • visualization
      ...(懒得画图,有空再补)

    • 说明
      添加节点后,first 指向的是最新添加的
      具体添加和删除的原理这篇就先不细说了

    相关文章

      网友评论

          本文标题:Linux kernel 数据结构 hlist (2)

          本文链接:https://www.haomeiwen.com/subject/xirnzktx.html