内核数据结构之链表

一、定义

内核链表与普通的链表类似,但是采用了不一样的结构。你以为的链表是这样的

 

也就是分为指针和body,body用于存储数据,指针用于指向上游和下游节点。然而在内核中,事情并没有那么简单。内核的链表表示大概是这样的

 

   

 

瞅见没有,如果你以为它只是在链表中指向上下游的话,你就错了骚年。内核的实现是将链表节点塞入数据结构。这是内核链表数据结构

struct list_head{

  struct list_head *next;

  struct list_head *prev;

}

 

struct bird{

  char wing;

  unsigned int color;

  struct list_head list;

}

 

如此这般,这般如此。但是这样就带来一个问题,也就是怎么从一个链表节点(list_head)来获取整个对象呢?这里就引入了container_of这个宏,container_of的作用的通过结构体成员变量地址获取这个结构体的地址,关于这个宏,定义如下

#define container_of(ptr, type, member)({
     const typeof(((type *)0) -> member) *_mptr = (ptr);
    (type *) (char *) _mptr - offsetof(type, member);
})

这个宏成立的原理是,在c语言中一个给定结构中的变量偏移在编译的时候地址就已经被ABI固定下来了。是不是很厉害呢,通过这样,我们就能通过一个成员变量来找到整个结构体了,这个宏的具体解析可以参考 https://zhuanlan.zhihu.com/p/54932270。 这样一来我们就可以通过一个简单的结构来访问链表的成员了。

#define list_entry(ptr, type, member) container_of(ptr, type, member)

这里再顺便说一句,内核中的链表都是循环链表

二、curd

  定义一个链表:

    首先先初始化一个对象bird,然后调用INIT_LIST_HEAD(&bird->list),或者如果在变量创建的时候初始化链表,就是只要将INIT_LIST_HEAD(bird.list)赋值给成员就好了

  向链表中增加一个节点:

    list_add(struct list_head *new, struct list_head *head)

  对于循环链表,可以将任何节点作为头节点,所以如果要创建一个bird节点b,并加入bird_list链表中,就可以用list_add(&b -> list, &bird_list)

  从链表中删除一个节点

    list_del(&f -> list)

  只需要传入节点,这里面会根据这个节点的上下游指针自动完成删除和将链表节点接上。

  其他操作不在赘述,需要的可以去网上查一下

三、遍历链表

  遍历链表就是用的刚才说的list_entry()宏,内核中一般用list_for_each_entry(pos, head, member)来遍历列表,其中用了list_entry()宏,应用实例如下,来自内核中文件系统的更新通知机制

复制代码

static strucet inotify_watch *inode_find_handle(struct inode *inode, struct inotify_handle *ih){
     struct inotify_watch *watch;
     list_for_entry(watch, &inode->inotify_watches, i_list){
        if(watch->ih == ih) return watch;
}    
return NULL;
}

复制代码

  同时也可以进行反向遍历列表。在遍历列表的过程中,我们是假设链表结构不会变更的,所以如果在想要在遍历的过程中变更,要记得进行相应的适配,防止出现错误

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值