Linux kernel 数据结构 hlist (2)

本文内容:添加节点,删除节点相关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 指向的是最新添加的
    具体添加和删除的原理这篇就先不细说了

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容