ubuntu内核list.h 的分析与应用

本文深入探讨了Ubuntu内核中list.h提供的双向循环链表操作,包括链表的初始化、元素添加、删除、替换以及遍历等方法。通过示例代码,详细解释了list_add、list_del、list_entry等关键函数的使用,并介绍了for循环遍历链表的各种技巧,如普通遍历、安全遍历以及从指定节点开始的遍历等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内核list (双向循环链表)

类型:
struct list_head {

 struct list_head *next, *prev;
};


链表的初始化(两种方式):
1. LIST_HEAD 定义一个头,并且初始化为循环链表
2. INIT_LIST_HEAD(内联函数)初始化为循环链表

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
 struct list_head name = LIST_HEAD_INIT(name)

static inline void INIT_LIST_HEAD(struct list_head *list)
{
 list->next = list;
 list->prev = list;
}


添加元素(两种方式):
1. 头插(list_add) :__list_add(new, head, head->next);
2. 尾插(list_add_tail) :__list_add(new, head->prev, head);
       两中方式本质相同往两个元素中间插入元素。
     (双向循环链表特点的体现)

删除元素(一种方式):
1. (list_del): __list_del(entry->prev, entry->next) 让两边元素相互指向
       让被删除元素指向LIST_POISON队列,让系统销毁
2. (list_del_init):将被删除元素初始化为新的双向循环列表

替换节点:
1. list_replace:修改新元素的指向即可
2. list_replace_init:修改新元素的指向即可,并将旧元素初始化为新的双向循环列表


list_move: 删除一个头部元素,在向头部插入一个新元素

判断是否为最后一个元素:list_is_last
判空:list_empty 和 list_empty_careful

list_entry(找到某个节点的起始位置): 分析
#define list_entry(ptr, type, member) \
 container_of(ptr, type, member)

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

// 将值赋值给变量,并且用const修饰,可以防止无意修改变量的值
// offset也做了改动
#define container_of(ptr, type, member) ({   \
 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
 (type *)( (char *)__mptr - offsetof(type,member) );})

之前版本使用的是:
#define list_entry(ptr, type, member) \
 ((type*)((char*)ptr – (unsigned long)(((type*)0)->member)))


 

一. 链表的for 循环头部:

0. 遍历时使用到的工具

    1. list_entry 通过节点的指针域找到节点的起始地址
      #define container_of(ptr, type, member) ({\
            const typeof( ((type *)0)->member ) *__mptr = (ptr);\
            (type *)( (char *)__mptr - offsetof(type,member) );})
    2. 

1. 向后遍历

    1. 普通的for 循环,只适合遍历,
        注意pos的类型是struct list_head
        list_for_each(pos, head) \
            for (pos = (head)->next; pos != (head); pos = pos->next)

    2. 在释放的时候使用,其中的n 可以指向已释放节点的下一个节点,
       注意pos 和n 的类型都是struct list_head
 list_for_each_safe(pos, n, head) \
            for (pos = (head)->next, n = pos->next; pos != (head); \
                  pos = n, n = pos->next)

    3. 普通的for 循环,只适合遍历,
        注意pos 的类型是用户定义的结构体
      list_for_each_entry (pos, head, member) \
 for (pos = list_first_entry(head, typeof(*pos), member);
                  &pos->member != (head);  \
                  pos = list_next_entry(pos, member))
    4. 继续遍历链表,从pos 的下一个开始</span>
        注意和3 中的一样pos 的初始值是链表中的某个节点
       #define list_for_each_entry_continue(pos, head, member)
     for (pos = list_next_entry(pos, member);
            &pos->member != (head);
            pos = list_next_entry(pos, member))


    5. 遍历链表从pos 开始
        和4 基本相似,
        #define list_for_each_entry_from(pos, head, member)
              for (; &pos->member != (head);
            pos = list_next_entry(pos, member))

    其他的就是给以上的加个safe
2. 向前遍历
    和上边的一样,实质将next 改成prev 即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值